From e191abff9c06de17ed12fc2f08b20b5fae3fb8b6 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 29 Apr 2024 11:06:15 +0200 Subject: [PATCH 01/24] initial steps to tree-shake non-free code --- config/webpack/webpack.config.js | 11 ++++--- packages/js/src/externals/analysis.js | 43 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 packages/js/src/externals/analysis.js diff --git a/config/webpack/webpack.config.js b/config/webpack/webpack.config.js index c52cae71095..c8bf6598032 100644 --- a/config/webpack/webpack.config.js +++ b/config/webpack/webpack.config.js @@ -33,10 +33,13 @@ module.exports = [ ), baseConfig( { - entry: yoastPackages.reduce( ( memo, packageName ) => { - memo[ yoastExternals[ packageName ] ] = "./node_modules/" + packageName; - return memo; - }, {} ), + entry: { + ...yoastPackages.reduce( ( memo, packageName ) => { + memo[ yoastExternals[ packageName ] ] = "./node_modules/" + packageName; + return memo; + }, {} ), + analysis: "./packages/js/src/externals/analysis.js", + }, output: { path: paths.jsDist + "/externals", filename: outputFilename, diff --git a/packages/js/src/externals/analysis.js b/packages/js/src/externals/analysis.js new file mode 100644 index 00000000000..244a22dc4f2 --- /dev/null +++ b/packages/js/src/externals/analysis.js @@ -0,0 +1,43 @@ +/** + * Ugly work-around alert. + * Using an indirect path to prevent a circular dependency. + * This way, we prevent the dependency on the `yoast-seo-analysis-package`. + * + * Ideally, this would be a configuration without the `yoastseo` external. + * But that would require the config with a different DependencyExtractionWebpackPlugin configuration. + */ +const { + App, + TaxonomyAssessor, + + Paper, + + AnalysisWebWorker, + AnalysisWorkerWrapper, + createWorker, + + assessments, + bundledPlugins, + helpers, + markers, + interpreters, + languageProcessing, + + DIFFICULTY, +} = require( "yoastseo/build" ); + +module.exports = { + App, + TaxonomyAssessor, + Paper, + AnalysisWebWorker, + AnalysisWorkerWrapper, + createWorker, + assessments, + bundledPlugins, + helpers, + markers, + interpreters, + languageProcessing, + DIFFICULTY, +}; From 588d0468f7da0c4687a5dbc5a599f85449b2a259 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 27 Aug 2024 17:11:50 +0200 Subject: [PATCH 02/24] Remove the override of the external analysis --- config/webpack/webpack.config.js | 11 +++---- packages/js/src/externals/analysis.js | 43 --------------------------- 2 files changed, 4 insertions(+), 50 deletions(-) delete mode 100644 packages/js/src/externals/analysis.js diff --git a/config/webpack/webpack.config.js b/config/webpack/webpack.config.js index 6c0a24d9ab8..bc5011a2ee1 100644 --- a/config/webpack/webpack.config.js +++ b/config/webpack/webpack.config.js @@ -45,13 +45,10 @@ module.exports = [ ), baseConfig( { - entry: { - ...yoastPackages.reduce( ( memo, packageName ) => { - memo[ yoastExternals[ packageName ] ] = "./node_modules/" + packageName; - return memo; - }, {} ), - analysis: "./packages/js/src/externals/analysis.js", - }, + entry: yoastPackages.reduce( ( memo, packageName ) => { + memo[ yoastExternals[ packageName ] ] = "./node_modules/" + packageName; + return memo; + }, {} ), output: { path: paths.jsDist + "/externals", filename: outputFilename, diff --git a/packages/js/src/externals/analysis.js b/packages/js/src/externals/analysis.js deleted file mode 100644 index 244a22dc4f2..00000000000 --- a/packages/js/src/externals/analysis.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Ugly work-around alert. - * Using an indirect path to prevent a circular dependency. - * This way, we prevent the dependency on the `yoast-seo-analysis-package`. - * - * Ideally, this would be a configuration without the `yoastseo` external. - * But that would require the config with a different DependencyExtractionWebpackPlugin configuration. - */ -const { - App, - TaxonomyAssessor, - - Paper, - - AnalysisWebWorker, - AnalysisWorkerWrapper, - createWorker, - - assessments, - bundledPlugins, - helpers, - markers, - interpreters, - languageProcessing, - - DIFFICULTY, -} = require( "yoastseo/build" ); - -module.exports = { - App, - TaxonomyAssessor, - Paper, - AnalysisWebWorker, - AnalysisWorkerWrapper, - createWorker, - assessments, - bundledPlugins, - helpers, - markers, - interpreters, - languageProcessing, - DIFFICULTY, -}; From 01902598c187ea61d65892b8d26c783cdfcbf616 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 27 Aug 2024 17:12:33 +0200 Subject: [PATCH 03/24] Extract the feedback strings out of the assessments --- .../readability/WordComplexityAssessment.js | 61 ++++++++-------- .../seo/KeyphraseDistributionAssessment.js | 72 ++++++++----------- 2 files changed, 59 insertions(+), 74 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index a3a1e3d6b1f..87b1dce26ca 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -1,4 +1,3 @@ -import { __, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; @@ -16,6 +15,11 @@ export default class WordComplexityAssessment extends Assessment { * Sets the identifier and the config. * * @param {object} config The configuration to use. + * @param {number} [config.scores.acceptableAmount] The score to return if the text has an acceptable amount of complex words. + * @param {number} [config.scores.goodAmount] The score to return if the text has a good amount of complex words. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {function} [config.getResultText] The function that returns the result text. * * @returns {void} */ @@ -31,12 +35,6 @@ export default class WordComplexityAssessment extends Assessment { urlCallToAction: "https://yoa.st/4lt", }; - /* - * translators: This is the name of the 'Word complexity' readability assessment. - * It appears before the feedback in the analysis, for example in the feedback string: - * "Word complexity: You are not using too many complex words, which makes your text easy to read. Good job!" - */ - this.name = __( "Word complexity", "wordpress-seo-premium" ); this.identifier = "wordComplexity"; this._config = merge( defaultConfig, config ); @@ -68,47 +66,48 @@ export default class WordComplexityAssessment extends Assessment { /** * Calculates word complexity word result. * - * @returns {object} Object containing the score, the result text and the information whether there is a mark.. + * @returns {object} Object containing the score, the result text and the information whether there is a mark. */ calculateResult() { const complexWordsPercentage = this._wordComplexity.percentage; const hasMarks = complexWordsPercentage > 0; - const assessmentLink = this._config.urlTitle + this.name + ""; + const { goodAmount, acceptableAmount } = this.getFeedbackStrings(); if ( complexWordsPercentage < 10 ) { return { score: this._config.scores.goodAmount, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s expands to the title of the "Word complexity" assessment (translated to the current language) - and links to an article on yoast.com.*/ - __( - "%1$s: You are not using too many complex words, which makes your text easy to read. Good job!", - "wordpress-seo-premium" - ), - assessmentLink - ), + resultText: goodAmount, }; } return { score: this._config.scores.acceptableAmount, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s expands to the title of the "Word complexity" assessment (translated to the current language) - and links to an article on yoast.com. %2$s expand to the percentage of the complex words found in the text. - %3$s expand to a link on yoast.com, %4$s expands to the anchor end tag. */ - __( - "%1$s: %2$s of the words in your text are considered complex. %3$sTry to use shorter and more familiar words to improve readability%4$s.", - "wordpress-seo-premium" - ), - assessmentLink, - complexWordsPercentage + "%", - this._config.urlCallToAction, - "" - ), + resultText: acceptableAmount, }; } + /** + * Gets the feedback strings for the word complexity assessment. + * + * @returns {{acceptableAmount: string, goodAmount: string}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.getResultText ) { + return { + acceptableAmount: "%1$sWord complexity%4$s: %2$s of the words in your text are considered complex. %3$sTry to use shorter and more familiar words to improve readability%4$s.", + goodAmount: "%1$sWord complexity%4$s: You are not using too many complex words, which makes your text easy to read. Good job!", + }; + } + const complexWordsPercentage = this._wordComplexity.percentage; + + return this._config.getResultText()( { + complexWordsPercentage, + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + } ); + } + /** * Marks text for the word complexity assessment. * diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index 7a847ac2313..dec7c936d6c 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -1,4 +1,3 @@ -import { __, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; @@ -26,6 +25,7 @@ class KeyphraseDistributionAssessment extends Assessment { * @param {number} [config.scores.consideration] The score to return if there are no keyword occurrences. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {function} [config.getResultText] The function that returns the result text. * * @returns {void} */ @@ -87,22 +87,18 @@ class KeyphraseDistributionAssessment extends Assessment { calculateResult() { const distributionScore = this._keyphraseDistribution.keyphraseDistributionScore; const hasMarks = this._keyphraseDistribution.sentencesToHighlight.length > 0; + const { + good: goodResultText, + okay: okayResultText, + bad: badResultText, + consideration: considerationResultText, + } = this.getFeedbackStrings(); if ( distributionScore === 100 ) { return { score: this._config.scores.consideration, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links to Yoast.com articles, - %3$s expands to the anchor end tag */ - __( - "%1$sKeyphrase distribution%3$s: %2$sInclude your keyphrase or its synonyms in the text so that we can check keyphrase distribution%3$s.", - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: considerationResultText, }; } @@ -110,17 +106,7 @@ class KeyphraseDistributionAssessment extends Assessment { return { score: this._config.scores.bad, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links to Yoast.com articles, - %3$s expands to the anchor end tag */ - __( - "%1$sKeyphrase distribution%3$s: Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: badResultText, }; } @@ -130,35 +116,35 @@ class KeyphraseDistributionAssessment extends Assessment { return { score: this._config.scores.okay, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links to Yoast.com articles, - %3$s expands to the anchor end tag */ - __( - "%1$sKeyphrase distribution%3$s: Uneven. Some parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: okayResultText, }; } return { score: this._config.scores.good, hasMarks: hasMarks, - resultText: sprintf( - /* translators: %1$s expands to links to Yoast.com articles, %2$s expands to the anchor end tag */ - __( - "%1$sKeyphrase distribution%2$s: Good job!", - "wordpress-seo-premium" - ), - this._config.urlTitle, - "" - ), + resultText: goodResultText, }; } + /** + * Gets the feedback strings for the keyphrase distribution assessment. + * + * @returns {{good: string, okay: string, bad: string, consideration}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.getResultText ) { + return { + good: "%1$sKeyphrase distribution%2$s: Good job!", + okay: "%1$sKeyphrase distribution%3$s: Uneven. Some parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", + bad: "%1$sKeyphrase distribution%3$s: Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", + consideration: "%1$sKeyphrase distribution%3$s: %2$sInclude your keyphrase or its synonyms in the text so that we can check keyphrase distribution%3$s.", + }; + } + + return this._config.getResultText()( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); + } + /** * Creates a marker for all content words in keyphrase and synonyms. * From c2d622153c2938a4f89ef8d740f3a6d0d833a622 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 28 Aug 2024 12:50:31 +0200 Subject: [PATCH 04/24] pass the method to get the feedback string as part of callbacks config --- .../readability/WordComplexityAssessment.js | 10 +++++++--- .../seo/KeyphraseDistributionAssessment.js | 12 +++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index 87b1dce26ca..e62b7e3568b 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -19,7 +19,7 @@ export default class WordComplexityAssessment extends Assessment { * @param {number} [config.scores.goodAmount] The score to return if the text has a good amount of complex words. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -89,11 +89,15 @@ export default class WordComplexityAssessment extends Assessment { /** * Gets the feedback strings for the word complexity assessment. + * Please note if you want to override the default feedback strings, you can use the `config.callbacks.getResultText` function. + * The callback function should return an object with the following properties: + * - acceptableAmount: string + * - goodAmount: string * * @returns {{acceptableAmount: string, goodAmount: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.getResultText ) { + if ( ! this._config.callbacks.getResultText ) { return { acceptableAmount: "%1$sWord complexity%4$s: %2$s of the words in your text are considered complex. %3$sTry to use shorter and more familiar words to improve readability%4$s.", goodAmount: "%1$sWord complexity%4$s: You are not using too many complex words, which makes your text easy to read. Good job!", @@ -101,7 +105,7 @@ export default class WordComplexityAssessment extends Assessment { } const complexWordsPercentage = this._wordComplexity.percentage; - return this._config.getResultText()( { + return this._config.callbacks.getResultText( { complexWordsPercentage, urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index dec7c936d6c..fc0798aadf4 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -25,7 +25,7 @@ class KeyphraseDistributionAssessment extends Assessment { * @param {number} [config.scores.consideration] The score to return if there are no keyword occurrences. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -129,11 +129,17 @@ class KeyphraseDistributionAssessment extends Assessment { /** * Gets the feedback strings for the keyphrase distribution assessment. + * Please note if you want to override the default feedback strings, you can use the `config.callbacks.getResultText` function. + * The callback function should return an object with the following properties: + * - good: string + * - okay: string + * - bad: string + * - consideration: string * * @returns {{good: string, okay: string, bad: string, consideration}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.getResultText ) { + if ( ! this._config.callbacks.getResultText ) { return { good: "%1$sKeyphrase distribution%2$s: Good job!", okay: "%1$sKeyphrase distribution%3$s: Uneven. Some parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", @@ -142,7 +148,7 @@ class KeyphraseDistributionAssessment extends Assessment { }; } - return this._config.getResultText()( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); + return this._config.callbacks.getResultText( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); } /** From 11a6495a49befc7383a530044221a093f857f534 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 28 Aug 2024 15:15:24 +0200 Subject: [PATCH 05/24] Extract feedback strings out of Text alignment and text title assessments --- .../readability/TextAlignmentAssessment.js | 71 ++++++++++--------- .../readability/WordComplexityAssessment.js | 4 +- .../seo/KeyphraseDistributionAssessment.js | 4 +- .../assessments/seo/TextTitleAssessment.js | 55 ++++++++------ 4 files changed, 73 insertions(+), 61 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js index 9cf8f2b23b0..88f044fe683 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js @@ -1,4 +1,3 @@ -import { _n, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; @@ -16,6 +15,11 @@ export default class TextAlignmentAssessment extends Assessment { * Constructs a new TextAlignmentAssessment. * * @param {object} config The configuration to use. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {object} [config.scores] The scores to use for the assessment. + * @param {number} [config.scores.bad] The score to return if the text has an over-use of center-alignment. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -45,15 +49,15 @@ export default class TextAlignmentAssessment extends Assessment { */ getResult( paper, researcher ) { const longCenterAlignedTexts = researcher.getResearch( "getLongCenterAlignedTexts" ); - const numberOfLongCenterAlignedTexts = longCenterAlignedTexts.length; + this.numberOfLongCenterAlignedTexts = longCenterAlignedTexts.length; const assessmentResult = new AssessmentResult(); // We don't want to show the assessment and its feedback when the paper doesn't contain center-aligned text. - if ( numberOfLongCenterAlignedTexts === 0 ) { + if ( this.numberOfLongCenterAlignedTexts === 0 ) { return assessmentResult; } - const calculatedScore = this.calculateResult( paper, numberOfLongCenterAlignedTexts ); + const calculatedScore = this.calculateResult( paper, this.numberOfLongCenterAlignedTexts ); assessmentResult.setScore( calculatedScore.score ); assessmentResult.setText( calculatedScore.resultText ); @@ -116,45 +120,44 @@ export default class TextAlignmentAssessment extends Assessment { * @returns {Object} The calculated result. */ calculateResult( paper, numberOfLongCenterAlignedTexts ) { + const { rightToLeft, leftToRight } = this.getFeedbackStrings(); if ( numberOfLongCenterAlignedTexts > 0 ) { if ( paper.getWritingDirection() === "RTL" ) { return { score: this._config.scores.bad, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag, - %4$s expands to the number of the long center-aligned sections in the text */ - _n( - "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it right-aligned%3$s.", - "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. " + - "%2$sWe recommend making them right-aligned%3$s.", - numberOfLongCenterAlignedTexts, - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "", - numberOfLongCenterAlignedTexts - ), + resultText: rightToLeft, }; } return { score: this._config.scores.bad, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag, - %4$s expands to the number of the long center-aligned sections in the text */ - _n( - "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it left-aligned%3$s.", - "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. " + - "%2$sWe recommend making them left-aligned%3$s.", - numberOfLongCenterAlignedTexts, - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "", - numberOfLongCenterAlignedTexts - ), + resultText: leftToRight, }; } } + + /** + * Returns the feedback strings for the assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * This callback function should return an object with the following properties: + * - rightToLeft: string + * - leftToRight: string + * The singular strings are used when there is only one long center-aligned text, the plural strings are used when there are multiple. + * rightToLeft is for the feedback string that is shown when the writing direction is right-to-left. + * leftToRight is for the feedback string that is shown when the writing direction is left-to-right. + * @returns {{leftToRight: string, rightToLeft: string}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultText ) { + return { + rightToLeft: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", + leftToRight: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them left-aligned%3$s.", + }; + } + + return this._config.callbacks.getResultText( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + numberOfLongCenterAlignedTexts: this.numberOfLongCenterAlignedTexts, + } ); + } } diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index e62b7e3568b..5a2ab149e13 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -89,7 +89,7 @@ export default class WordComplexityAssessment extends Assessment { /** * Gets the feedback strings for the word complexity assessment. - * Please note if you want to override the default feedback strings, you can use the `config.callbacks.getResultText` function. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. * The callback function should return an object with the following properties: * - acceptableAmount: string * - goodAmount: string @@ -106,9 +106,9 @@ export default class WordComplexityAssessment extends Assessment { const complexWordsPercentage = this._wordComplexity.percentage; return this._config.callbacks.getResultText( { - complexWordsPercentage, urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, + complexWordsPercentage, } ); } diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index fc0798aadf4..560eeafd06f 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -129,14 +129,14 @@ class KeyphraseDistributionAssessment extends Assessment { /** * Gets the feedback strings for the keyphrase distribution assessment. - * Please note if you want to override the default feedback strings, you can use the `config.callbacks.getResultText` function. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. * The callback function should return an object with the following properties: * - good: string * - okay: string * - bad: string * - consideration: string * - * @returns {{good: string, okay: string, bad: string, consideration}} The feedback strings. + * @returns {{good: string, okay: string, bad: string, consideration: string}} The feedback strings. */ getFeedbackStrings() { if ( ! this._config.callbacks.getResultText ) { diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 5f90c866806..219e50a4b23 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -1,4 +1,3 @@ -import { __, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; @@ -14,6 +13,12 @@ export default class TextTitleAssessment extends Assessment { * Constructs a text title assessment. * * @param {object} config The config to use for the assessment. + * @param {object} config.scores The scores to use for the assessment. + * @param {number} config.scores.good The score to return if the text has a title. + * @param {number} config.scores.bad The score to return if the text does not have a title. + * @param {string} config.urlTitle The URL to the article about this assessment. + * @param {string} config.urlCallToAction The URL to the help article for this assessment. + * @param {function} config.callbacks.getResultText The function that returns the result text. * * @returns {void} */ @@ -72,38 +77,42 @@ export default class TextTitleAssessment extends Assessment { * @returns {{resultText: string, score}} Result object with score and text. */ calculateResult( textTitleData ) { + const { good: goodResultText, bad: badResultText } = this.getFeedbackStrings(); // GOOD result when the text has a title. if ( textTitleData ) { return { score: this._config.scores.good, - resultText: sprintf( - /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. */ - __( - "%1$sTitle%2$s: Your page has a title. Well done!", - "wordpress-seo-premium" - ), - this._config.urlTitle, - "" - ), + resultText: goodResultText, }; } // BAD if the text is missing a title. return { score: this._config.scores.bad, - resultText: sprintf( - /** - * translators: - * %1$s and %2$s expands to a link on yoast.com, %3$s expands to the anchor end tag. - */ - __( - "%1$sTitle%3$s: Your page does not have a title yet. %2$sAdd one%3$s!", - "wordpress-seo-premium" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: badResultText, }; } + + /** + * Gets the feedback strings for the text title assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * The callback function should return an object with the following properties: + * - good: string + * - bad: string + * + * @returns {{good: string, bad: string}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultText ) { + return { + good: "%1$sTitle%2$s: Your page has a title. Well done!", + bad: "%1$sTitle%3$s: Your page does not have a title yet. %2$sAdd one%3$s!", + }; + } + + return this._config.callbacks.getResultText( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + } ); + } } From 7e18208b6992e5563acac1d5b7958768d789d14b Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 29 Aug 2024 12:19:56 +0200 Subject: [PATCH 06/24] Extract the feedback strings out of List assessment --- .../assessments/readability/ListAssessment.js | 58 ++++++++++++------- .../readability/TextAlignmentAssessment.js | 3 + 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js index 45e89893e0e..2d0a5544196 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js @@ -14,6 +14,12 @@ export default class ListAssessment extends Assessment { * Sets the identifier and the config. * * @param {object} config The configuration to use. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {object} [config.scores] The scores to use for the assessment. + * @param {number} [config.scores.bad] The score to return if the text has no list. + * @param {number} [config.scores.good] The score to return if the text has a list. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -21,8 +27,8 @@ export default class ListAssessment extends Assessment { super(); const defaultConfig = { - urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify38" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify39" ), + urlTitle: "https://yoa.st/shopify38", + urlCallToAction: "https://yoa.st/shopify39", scores: { bad: 3, good: 9, @@ -30,6 +36,8 @@ export default class ListAssessment extends Assessment { }; this._config = merge( defaultConfig, config ); + this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); + this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); this.identifier = "listsPresence"; } @@ -86,36 +94,42 @@ export default class ListAssessment extends Assessment { * @returns {Object} The calculated result. */ calculateResult() { + const { good: goodResultText, bad: badResultText } = this.getFeedbackStrings(); // Text with at least one list. if ( this.textContainsList ) { return { score: this._config.scores.good, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag */ - __( - "%1$sLists%2$s: There is at least one list on this page. Great!", - "yoast-woo-seo" - ), - this._config.urlTitle, - "" - ), + resultText: goodResultText, }; } // Text with no lists. return { score: this._config.scores.bad, - resultText: sprintf( - /* translators: %1$s expands to a link on yoast.com, - * %2$s expands to the anchor end tag. */ - __( - "%1$sLists%3$s: No lists appear on this page. %2$sAdd at least one ordered or unordered list%3$s!", - "yoast-woo-seo" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: badResultText, }; } + + /** + * Gets the feedback strings for the assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * The callback function should return an object with the following properties: + * - good: string + * - bad: string + * + * @returns {{good: string, bad: string}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultText ) { + return { + good: "%1$sLists%2$s: There is at least one list on this page. Great!", + bad: "%1$sLists%3$s: No lists appear on this page. %2$sAdd at least one ordered or unordered list%3$s!", + }; + } + + return this._config.callbacks.getResultText( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + } ); + } } diff --git a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js index 88f044fe683..735129a40fe 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js @@ -149,7 +149,10 @@ export default class TextAlignmentAssessment extends Assessment { getFeedbackStrings() { if ( ! this._config.callbacks.getResultText ) { return { + // %1$s is the `urlTitle`, %2$s is the `urlCallToAction`, %3$s expands to the anchor end tag ``, %4$s expands to the number of the long center-aligned sections in the text */ + // Singular RTL: "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it right-aligned%3$s.", rightToLeft: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", + // Singular LTR: "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it left-aligned%3$s.", leftToRight: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them left-aligned%3$s.", }; } From 8f8a1826c6c4d67d812fd63f86d1ccfe02ca4c5f Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 29 Aug 2024 12:20:18 +0200 Subject: [PATCH 07/24] Don't register the List assessment via the assessors --- .../yoastseo/src/scoring/productPages/contentAssessor.js | 5 ----- .../src/scoring/productPages/cornerstone/contentAssessor.js | 5 ----- 2 files changed, 10 deletions(-) diff --git a/packages/yoastseo/src/scoring/productPages/contentAssessor.js b/packages/yoastseo/src/scoring/productPages/contentAssessor.js index 82dc012adf3..27c4341271f 100644 --- a/packages/yoastseo/src/scoring/productPages/contentAssessor.js +++ b/packages/yoastseo/src/scoring/productPages/contentAssessor.js @@ -10,7 +10,6 @@ const { TransitionWordsAssessment, PassiveVoiceAssessment, TextPresenceAssessment, - ListAssessment, } = assessments.readability; /** @@ -57,10 +56,6 @@ const ProductContentAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.textPresenceUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.textPresenceCTAUrl ), } ), - new ListAssessment( { - urlTitle: createAnchorOpeningTag( options.listsUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.listsCTAUrl ), - } ), ]; }; diff --git a/packages/yoastseo/src/scoring/productPages/cornerstone/contentAssessor.js b/packages/yoastseo/src/scoring/productPages/cornerstone/contentAssessor.js index f3e1e65e2d5..3253f2e84d8 100644 --- a/packages/yoastseo/src/scoring/productPages/cornerstone/contentAssessor.js +++ b/packages/yoastseo/src/scoring/productPages/cornerstone/contentAssessor.js @@ -10,7 +10,6 @@ const { TransitionWordsAssessment, PassiveVoiceAssessment, TextPresenceAssessment, - ListAssessment, } = assessments.readability; /** @@ -64,10 +63,6 @@ const ProductCornerstoneContentAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.textPresenceUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.textPresenceCTAUrl ), } ), - new ListAssessment( { - urlTitle: createAnchorOpeningTag( options.listsUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.listsCTAUrl ), - } ), ]; }; From 92b82dfebc9040650c91d45e5477376d47e11e96 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 29 Aug 2024 17:42:40 +0200 Subject: [PATCH 08/24] Extract the translation strings out of Image ALt and Product SKU assessments --- .../assessments/readability/ListAssessment.js | 1 - .../assessments/seo/ImageAltTagsAssessment.js | 83 +++++++------- .../assessments/seo/ProductSKUAssessment.js | 106 +++++++++--------- .../assessments/seo/TextTitleAssessment.js | 6 +- .../productPages/cornerstone/seoAssessor.js | 13 --- .../src/scoring/productPages/seoAssessor.js | 13 --- 6 files changed, 102 insertions(+), 120 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js index 2d0a5544196..b4cba7957d2 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js @@ -1,4 +1,3 @@ -import { __, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js index 6ff161b627b..7eb11d1a50c 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js @@ -1,4 +1,3 @@ -import { __, _n, sprintf } from "@wordpress/i18n"; import { merge } from "lodash"; import Assessment from "../assessment"; @@ -13,6 +12,11 @@ export default class ImageAltTagsAssessment extends Assessment { * Sets the identifier and the config. * * @param {object} config The configuration to use. + * @param {number} [config.scores.bad] The score to return if not all images have alt tags. + * @param {number} [config.scores.good] The score to return if all images have alt tags. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -24,12 +28,15 @@ export default class ImageAltTagsAssessment extends Assessment { bad: 3, good: 9, }, - urlTitle: createAnchorOpeningTag( "" ), - urlCallToAction: createAnchorOpeningTag( "" ), + urlTitle: "", + urlCallToAction: "", }; this.identifier = "imageAltTags"; this._config = merge( defaultConfig, config ); + + this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); + this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -67,28 +74,20 @@ export default class ImageAltTagsAssessment extends Assessment { } /** - * Calculates the result based on the availability of images in the text, including videos in product pages. + * Calculates the result based on the availability of images in the text. * * @returns {Object} The calculated result. */ calculateResult() { // The number of images with no alt tags. const imagesNoAlt = this.altTagsProperties.noAlt; + const { good: goodResultText, noneHasAltBad, someHaveAltBad } = this.getFeedbackStrings(); // None of the images has alt tags. if ( imagesNoAlt === this.imageCount ) { return { score: this._config.scores.bad, - resultText: sprintf( - /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag */ - __( - "%1$sImage alt tags%3$s: None of the images has alt attributes. %2$sAdd alt attributes to your images%3$s!", - "yoast-woo-seo" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: noneHasAltBad, }; } @@ -96,38 +95,42 @@ export default class ImageAltTagsAssessment extends Assessment { if ( imagesNoAlt > 0 ) { return { score: this._config.scores.bad, - resultText: sprintf( - /* translators: %3$s and %4$s expand to links on yoast.com, %5$s expands to the anchor end tag, - * %1$d expands to the number of images without alt tags, - * %2$d expands to the number of images found in the text, */ - _n( - "%3$sImage alt tags%5$s: %1$d image out of %2$d doesn't have alt attributes. %4$sAdd alt attributes to your images%5$s!", - "%3$sImage alt tags%5$s: %1$d images out of %2$d don't have alt attributes. %4$sAdd alt attributes to your images%5$s!", - imagesNoAlt, - "yoast-woo-seo" - ), - imagesNoAlt, - this.imageCount, - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + resultText: someHaveAltBad, }; } // All images have alt tags. return { score: this._config.scores.good, - resultText: sprintf( - /* translators: %1$s expands to a link on yoast.com, - * %2$s expands to the anchor end tag. */ - __( - "%1$sImage alt tags%2$s: All images have alt attributes. Good job!", - "yoast-woo-seo" - ), - this._config.urlTitle, - "" - ), + resultText: goodResultText, }; } + + /** + * Returns the feedback strings for the assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * This callback function should return an object with the following properties: + * - good: string + * - noneHasAltBad: string + * - someHaveAltBad: string + * + * @returns {{good: string, noneHasAltBad: string, someHaveAltBad: string}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultText ) { + return { + good: "%1$sImage alt tags%2$s: All images have alt attributes. Good job!", + noneHasAltBad: "%1$sImage alt tags%3$s: None of the images has alt attributes. %2$sAdd alt attributes to your images%3$s!", + // Singular: "%3$sImage alt tags%5$s: %1$d image out of %2$d doesn't have alt attributes. %4$sAdd alt attributes to your images%5$s!" + someHaveAltBad: "%3$sImage alt tags%5$s: %1$d images out of %2$d don't have alt attributes. %4$sAdd alt attributes to your images%5$s!", + }; + } + + return this._config.callbacks.getResultText( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + numberOfImagesWithoutAlt: this.altTagsProperties.noAlt, + totalNumberOfImages: this.imageCount, + } ); + } } diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index f74179c4aa7..f44c488d859 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -1,5 +1,4 @@ import { merge } from "lodash"; -import { __, sprintf } from "@wordpress/i18n"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -13,6 +12,15 @@ export default class ProductSKUAssessment extends Assessment { * Constructs a product SKU assessment. * * @param {Object} config Potential additional config for the assessment. + * @param {Object} [config.scores] The scores to use for the assessment. + * @param {number} [config.scores.good] The score to return if the product has a SKU. + * @param {number} [config.scores.ok] The score to return if the product doesn't have a SKU. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {boolean} [config.assessVariants] Whether to assess variants. + * @param {boolean} [config.addSKULocation] Whether to add the SKU location to the assessment result. + * @param {string} [config.editFieldName] The name of the field to edit. + * @param {function} [config.callbacks.getResultText] The function that returns the result text. * * @returns {void} */ @@ -24,20 +32,22 @@ export default class ProductSKUAssessment extends Assessment { good: 9, ok: 6, }, - urlTitle: createAnchorOpeningTag( "https://yoa.st/4lw" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/4lx" ), + urlTitle: "https://yoa.st/4lw", + urlCallToAction: "https://yoa.st/4lx", assessVariants: true, addSKULocation: false, }; this.identifier = "productSKU"; this._config = merge( defaultConfig, config ); + this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); + this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** - * Executes the assessment and returns an result based on the research. + * Executes the assessment and returns a result based on the research. * - * @param {Paper} paper The paper to use for the assessment. + * @param {Paper} paper The paper to use for the assessment. * * @returns {AssessmentResult} An assessment result with the score and formatted text. */ @@ -55,7 +65,8 @@ export default class ProductSKUAssessment extends Assessment { if ( assessmentResult.getScore() < 9 && this._config.shouldShowEditButton ) { assessmentResult.setHasJumps( true ); - assessmentResult.setEditFieldName( __( "SKU", "yoast-woo-seo" ) ); + // Provide `this._config.editFieldName` when initialize this assessment with the value "SKU". We recommend to provide the string as a translation string. + assessmentResult.setEditFieldName( this._config.editFieldName || "SKU" ); } return assessmentResult; @@ -63,10 +74,10 @@ export default class ProductSKUAssessment extends Assessment { /** * Checks whether the assessment is applicable. - * It is not applicable when the product has variants and we don't want to assess variants (this is the case for Shopify + * It is not applicable when the product has variants, and we don't want to assess variants (this is the case for Shopify * since we cannot at the moment easily access variant data in Shopify). * It is also not applicable when we cannot retrieve the SKU (this can be the case if other plugins remove/change the SKU - * input field in such as way that we cannot detect it. + * input field in such as way that we cannot detect it). * * @param {Paper} paper The paper to check. * @@ -97,43 +108,26 @@ export default class ProductSKUAssessment extends Assessment { /** * Returns a score based on whether the product (variants) have a SKU. * - * @param {Object} productSKUData Whether product has variants, global SKU, and variant SKU. - * @param {Object} config The configuration to use. + * @param {Object} productSKUData Whether product has variants, global SKU, and variant SKU. + * @param {Object} config The configuration to use. * * @returns {{score: number, text: string} | {}} The result object with score and text * or empty object if no score should be returned. */ scoreProductSKU( productSKUData, config ) { + const { good, okay } = this.getFeedbackStrings(); // Apply the following scoring conditions to products without variants. if ( [ "simple", "external", "grouped" ].includes( productSKUData.productType ) || ( productSKUData.productType === "variable" && ! productSKUData.hasVariants ) ) { if ( ! productSKUData.hasGlobalSKU ) { return { score: config.scores.ok, - text: sprintf( - // translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag. - __( - "%1$sSKU%3$s: Your product is missing a SKU." + - " %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", - "yoast-woo-seo" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + text: okay.withoutVariants, }; } return { score: config.scores.good, - text: sprintf( - // translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. - __( - "%1$sSKU%2$s: Your product has a SKU. Good job!", - "yoast-woo-seo" - ), - this._config.urlTitle, - "" - ), + text: good.withoutVariants, }; } else if ( productSKUData.productType === "variable" && productSKUData.hasVariants ) { // If we want to assess variants, if product has variants and not all variants have a SKU, return orange bullet. @@ -141,33 +135,43 @@ export default class ProductSKUAssessment extends Assessment { if ( ! productSKUData.doAllVariantsHaveSKU ) { return { score: config.scores.ok, - text: sprintf( - // translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag. - __( - "%1$sSKU%3$s: Not all your product variants have a SKU. " + - "You can add a SKU via the \"Variations\" tab in the Product data box." + - " %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", - "yoast-woo-seo" - ), - this._config.urlTitle, - this._config.urlCallToAction, - "" - ), + text: okay.withVariants, }; } return { score: config.scores.good, - text: sprintf( - // translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. - __( - "%1$sSKU%2$s: All your product variants have a SKU. Good job!", - "yoast-woo-seo" - ), - this._config.urlTitle, - "" - ), + text: good.withVariants, }; } return {}; } + + /** + * Gets the feedback strings for the assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * The callback function should return an object with the following properties: + * - good: {withoutVariants: string, withVariants: string} + * - okay: {withoutVariants: string, withVariants: string} + * + * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultText ) { + return { + good: { + withoutVariants: "%1$sSKU%2$s: Your product has a SKU. Good job!", + withVariants: "%1$sSKU%2$s: All your product variants have a SKU. Good job!", + }, + okay: { + withoutVariants: "%1$sSKU%3$s: Your product is missing a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + withVariants: "%1$sSKU%3$s: Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product data box. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + }, + }; + } + + return this._config.callbacks.getResultText( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + } ); + } } diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 219e50a4b23..73f740af435 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -29,12 +29,14 @@ export default class TextTitleAssessment extends Assessment { good: 9, bad: -10000, }, - urlTitle: createAnchorOpeningTag( "https://yoa.st/4nh" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/4ni" ), + urlTitle: "https://yoa.st/4nh", + urlCallToAction: "https://yoa.st/4ni", }; this.identifier = "textTitleAssessment"; this._config = merge( defaultConfig, config ); + this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); + this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** diff --git a/packages/yoastseo/src/scoring/productPages/cornerstone/seoAssessor.js b/packages/yoastseo/src/scoring/productPages/cornerstone/seoAssessor.js index dadd1666508..353251351df 100644 --- a/packages/yoastseo/src/scoring/productPages/cornerstone/seoAssessor.js +++ b/packages/yoastseo/src/scoring/productPages/cornerstone/seoAssessor.js @@ -14,7 +14,6 @@ const { SlugKeywordAssessment, MetaDescriptionLengthAssessment, SubheadingsKeywordAssessment, - ImageAltTagsAssessment, ImageKeyphraseAssessment, ImageCountAssessment, TextLengthAssessment, @@ -22,7 +21,6 @@ const { FunctionWordsInKeyphraseAssessment, SingleH1Assessment, ProductIdentifiersAssessment, - ProductSKUAssessment, } = assessments.seo; /** @@ -135,10 +133,6 @@ const ProductCornerstoneSEOAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.imageKeyphraseUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.imageKeyphraseCTAUrl ), } ), - new ImageAltTagsAssessment( { - urlTitle: createAnchorOpeningTag( options.imageAltTagsUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.imageAltTagsCTAUrl ), - } ), new ProductIdentifiersAssessment( { urlTitle: createAnchorOpeningTag( options.productIdentifierUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.productIdentifierCTAUrl ), @@ -146,13 +140,6 @@ const ProductCornerstoneSEOAssessor = function( researcher, options ) { productIdentifierOrBarcode: options.productIdentifierOrBarcode, shouldShowEditButton: options.shouldShowEditButtons, } ), - new ProductSKUAssessment( { - urlTitle: createAnchorOpeningTag( options.productSKUUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.productSKUCTAUrl ), - assessVariants: options.assessVariants, - addSKULocation: options.addSKULocation, - shouldShowEditButton: options.shouldShowEditButtons, - } ), ]; }; diff --git a/packages/yoastseo/src/scoring/productPages/seoAssessor.js b/packages/yoastseo/src/scoring/productPages/seoAssessor.js index ae3cdaad6f1..0e8a71c9a11 100644 --- a/packages/yoastseo/src/scoring/productPages/seoAssessor.js +++ b/packages/yoastseo/src/scoring/productPages/seoAssessor.js @@ -16,13 +16,11 @@ const { SubheadingsKeywordAssessment, ImageKeyphraseAssessment, ImageCountAssessment, - ImageAltTagsAssessment, TextLengthAssessment, PageTitleWidthAssessment, FunctionWordsInKeyphraseAssessment, SingleH1Assessment, ProductIdentifiersAssessment, - ProductSKUAssessment, } = assessments.seo; /** @@ -116,10 +114,6 @@ const ProductSEOAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.imageKeyphraseUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.imageKeyphraseCTAUrl ), } ), - new ImageAltTagsAssessment( { - urlTitle: createAnchorOpeningTag( options.imageAltTagsUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.imageAltTagsCTAUrl ), - } ), new ProductIdentifiersAssessment( { urlTitle: createAnchorOpeningTag( options.productIdentifierUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.productIdentifierCTAUrl ), @@ -127,13 +121,6 @@ const ProductSEOAssessor = function( researcher, options ) { productIdentifierOrBarcode: options.productIdentifierOrBarcode, shouldShowEditButton: options.shouldShowEditButtons, } ), - new ProductSKUAssessment( { - urlTitle: createAnchorOpeningTag( options.productSKUUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.productSKUCTAUrl ), - assessVariants: options.assessVariants, - addSKULocation: options.addSKULocation, - shouldShowEditButton: options.shouldShowEditButtons, - } ), ]; }; From 9a1599c6d9a4d7824a8a5862cc430521d60f5c00 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 14:25:37 +0200 Subject: [PATCH 09/24] Add a method to format strings to Assessment class --- .../yoastseo/src/scoring/assessments/assessment.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/src/scoring/assessments/assessment.js b/packages/yoastseo/src/scoring/assessments/assessment.js index e5ed31b0942..65f8e94a33f 100644 --- a/packages/yoastseo/src/scoring/assessments/assessment.js +++ b/packages/yoastseo/src/scoring/assessments/assessment.js @@ -1,5 +1,5 @@ /* eslint-disable no-unused-vars */ - +import { sprintf } from "@wordpress/i18n"; import { sanitizeString } from "../../languageProcessing"; import { filterShortcodesFromHTML, removeHtmlBlocks } from "../../languageProcessing/helpers"; @@ -46,6 +46,18 @@ class Assessment { return sanitizeString( text ).length >= contentNeededForAssessment; } + + /** + * Formats a string with the URL to the article about a specific assessment. + * + * @param {string} resultText The string to format. + * @param {string} urlTitle The URL to the article about a specific assessment. + * @param {string} urlCallToAction The URL to the help article for a specific assessment. + * @returns {string} The formatted string. + */ + formatResultText( resultText, urlTitle, urlCallToAction ) { + return sprintf( resultText, urlTitle, urlCallToAction, "" ); + } } /* eslint-enable no-unused-vars */ From ca80ed62a7aae35e9ef9def811d36fc7f4d3a010 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 14:29:06 +0200 Subject: [PATCH 10/24] Improve the default result texts. Now we return a formatted text --- .../assessments/readability/ListAssessment.js | 18 +++++++----- .../readability/TextAlignmentAssessment.js | 28 +++++++++++-------- .../readability/WordComplexityAssessment.js | 20 +++++++------ .../assessments/seo/ImageAltTagsAssessment.js | 24 ++++++++++------ .../seo/KeyphraseDistributionAssessment.js | 18 +++++++----- .../assessments/seo/ProductSKUAssessment.js | 28 +++++++++++++------ .../assessments/seo/TextTitleAssessment.js | 18 +++++++----- 7 files changed, 96 insertions(+), 58 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js index b4cba7957d2..06faff1174a 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -18,7 +18,7 @@ export default class ListAssessment extends Assessment { * @param {object} [config.scores] The scores to use for the assessment. * @param {number} [config.scores.bad] The score to return if the text has no list. * @param {number} [config.scores.good] The score to return if the text has a list. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -111,7 +111,7 @@ export default class ListAssessment extends Assessment { /** * Gets the feedback strings for the assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * The callback function should return an object with the following properties: * - good: string * - bad: string @@ -119,14 +119,18 @@ export default class ListAssessment extends Assessment { * @returns {{good: string, bad: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { - good: "%1$sLists%2$s: There is at least one list on this page. Great!", + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + good: "%1$sLists%3$s: There is at least one list on this page. Great!", bad: "%1$sLists%3$s: No lists appear on this page. %2$sAdd at least one ordered or unordered list%3$s!", }; + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, } ); diff --git a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js index 735129a40fe..a931a7b52e0 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import Mark from "../../../values/Mark"; @@ -19,7 +19,7 @@ export default class TextAlignmentAssessment extends Assessment { * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. * @param {object} [config.scores] The scores to use for the assessment. * @param {number} [config.scores.bad] The score to return if the text has an over-use of center-alignment. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -137,27 +137,33 @@ export default class TextAlignmentAssessment extends Assessment { /** * Returns the feedback strings for the assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * This callback function should return an object with the following properties: * - rightToLeft: string * - leftToRight: string * The singular strings are used when there is only one long center-aligned text, the plural strings are used when there are multiple. * rightToLeft is for the feedback string that is shown when the writing direction is right-to-left. * leftToRight is for the feedback string that is shown when the writing direction is left-to-right. + * * @returns {{leftToRight: string, rightToLeft: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { - // %1$s is the `urlTitle`, %2$s is the `urlCallToAction`, %3$s expands to the anchor end tag ``, %4$s expands to the number of the long center-aligned sections in the text */ - // Singular RTL: "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it right-aligned%3$s.", - rightToLeft: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", - // Singular LTR: "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it left-aligned%3$s.", - leftToRight: "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them left-aligned%3$s.", + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + rightToLeft: "%1$sAlignment%3$s: There are long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", + leftToRight: "%1$sAlignment%3$s: There are long sections of center-aligned text. %2$sWe recommend making them left-aligned%3$s.", }; + if ( this.numberOfLongCenterAlignedTexts === 1 ) { + defaultResultTexts.rightToLeft = "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it right-aligned%3$s."; + defaultResultTexts.leftToRight = "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it left-aligned%3$s."; + } + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, numberOfLongCenterAlignedTexts: this.numberOfLongCenterAlignedTexts, diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index 5a2ab149e13..513087a7eea 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import Mark from "../../../values/Mark"; @@ -19,7 +19,7 @@ export default class WordComplexityAssessment extends Assessment { * @param {number} [config.scores.goodAmount] The score to return if the text has a good amount of complex words. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -89,7 +89,7 @@ export default class WordComplexityAssessment extends Assessment { /** * Gets the feedback strings for the word complexity assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * The callback function should return an object with the following properties: * - acceptableAmount: string * - goodAmount: string @@ -97,15 +97,19 @@ export default class WordComplexityAssessment extends Assessment { * @returns {{acceptableAmount: string, goodAmount: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { - acceptableAmount: "%1$sWord complexity%4$s: %2$s of the words in your text are considered complex. %3$sTry to use shorter and more familiar words to improve readability%4$s.", - goodAmount: "%1$sWord complexity%4$s: You are not using too many complex words, which makes your text easy to read. Good job!", + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + acceptableAmount: "%1$sWord complexity%3$s: Some words in your text are considered complex. %2$sTry to use shorter and more familiar words to improve readability%3$s.", + goodAmount: "%1$sWord complexity%3$s: You are not using too many complex words, which makes your text easy to read. Good job!", }; + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } const complexWordsPercentage = this._wordComplexity.percentage; - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, complexWordsPercentage, diff --git a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js index 7eb11d1a50c..868fc1aa320 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -16,7 +16,7 @@ export default class ImageAltTagsAssessment extends Assessment { * @param {number} [config.scores.good] The score to return if all images have alt tags. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -108,7 +108,7 @@ export default class ImageAltTagsAssessment extends Assessment { /** * Returns the feedback strings for the assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * This callback function should return an object with the following properties: * - good: string * - noneHasAltBad: string @@ -117,16 +117,22 @@ export default class ImageAltTagsAssessment extends Assessment { * @returns {{good: string, noneHasAltBad: string, someHaveAltBad: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { - good: "%1$sImage alt tags%2$s: All images have alt attributes. Good job!", + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + good: "%1$sImage alt tags%3$s: All images have alt attributes. Good job!", noneHasAltBad: "%1$sImage alt tags%3$s: None of the images has alt attributes. %2$sAdd alt attributes to your images%3$s!", - // Singular: "%3$sImage alt tags%5$s: %1$d image out of %2$d doesn't have alt attributes. %4$sAdd alt attributes to your images%5$s!" - someHaveAltBad: "%3$sImage alt tags%5$s: %1$d images out of %2$d don't have alt attributes. %4$sAdd alt attributes to your images%5$s!", + someHaveAltBad: "%1$sImage alt tags%3$s: Some images don't have alt attributes. %2$sAdd alt attributes to your images%3$s!", }; + if ( this.imageCount === 1 ) { + defaultResultTexts.someHaveAltBad = "%1$sImage alt tags%3$s: One image doesn't have alt attributes. %2$sAdd alt attributes to your images%2$s!"; + } + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, numberOfImagesWithoutAlt: this.altTagsProperties.noAlt, diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index 560eeafd06f..afcfbde7a26 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -25,7 +25,7 @@ class KeyphraseDistributionAssessment extends Assessment { * @param {number} [config.scores.consideration] The score to return if there are no keyword occurrences. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -129,7 +129,7 @@ class KeyphraseDistributionAssessment extends Assessment { /** * Gets the feedback strings for the keyphrase distribution assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * The callback function should return an object with the following properties: * - good: string * - okay: string @@ -139,16 +139,20 @@ class KeyphraseDistributionAssessment extends Assessment { * @returns {{good: string, okay: string, bad: string, consideration: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { - good: "%1$sKeyphrase distribution%2$s: Good job!", + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + good: "%1$sKeyphrase distribution%3$s: Good job!", okay: "%1$sKeyphrase distribution%3$s: Uneven. Some parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", bad: "%1$sKeyphrase distribution%3$s: Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. %2$sDistribute them more evenly%3$s.", consideration: "%1$sKeyphrase distribution%3$s: %2$sInclude your keyphrase or its synonyms in the text so that we can check keyphrase distribution%3$s.", }; + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } - return this._config.callbacks.getResultText( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); } /** diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index f44c488d859..8bc482f8a61 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -20,7 +20,7 @@ export default class ProductSKUAssessment extends Assessment { * @param {boolean} [config.assessVariants] Whether to assess variants. * @param {boolean} [config.addSKULocation] Whether to add the SKU location to the assessment result. * @param {string} [config.editFieldName] The name of the field to edit. - * @param {function} [config.callbacks.getResultText] The function that returns the result text. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -36,6 +36,7 @@ export default class ProductSKUAssessment extends Assessment { urlCallToAction: "https://yoa.st/4lx", assessVariants: true, addSKULocation: false, + editFieldName: "SKU", }; this.identifier = "productSKU"; @@ -66,7 +67,7 @@ export default class ProductSKUAssessment extends Assessment { if ( assessmentResult.getScore() < 9 && this._config.shouldShowEditButton ) { assessmentResult.setHasJumps( true ); // Provide `this._config.editFieldName` when initialize this assessment with the value "SKU". We recommend to provide the string as a translation string. - assessmentResult.setEditFieldName( this._config.editFieldName || "SKU" ); + assessmentResult.setEditFieldName( this._config.editFieldName ); } return assessmentResult; @@ -148,7 +149,7 @@ export default class ProductSKUAssessment extends Assessment { /** * Gets the feedback strings for the assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * The callback function should return an object with the following properties: * - good: {withoutVariants: string, withVariants: string} * - okay: {withoutVariants: string, withVariants: string} @@ -156,20 +157,29 @@ export default class ProductSKUAssessment extends Assessment { * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { good: { - withoutVariants: "%1$sSKU%2$s: Your product has a SKU. Good job!", - withVariants: "%1$sSKU%2$s: All your product variants have a SKU. Good job!", + withoutVariants: "%1$sSKU%3$s: Your product has a SKU. Good job!", + withVariants: "%1$sSKU%3$s: All your product variants have a SKU. Good job!", }, okay: { withoutVariants: "%1$sSKU%3$s: Your product is missing a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", withVariants: "%1$sSKU%3$s: Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product data box. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", }, }; + defaultResultTexts.good = mapValues( + defaultResultTexts.good, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); + defaultResultTexts.okay = mapValues( + defaultResultTexts.okay, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); + return defaultResultTexts; } - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, } ); diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 73f740af435..948f18d8150 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -1,4 +1,4 @@ -import { merge } from "lodash"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -18,7 +18,7 @@ export default class TextTitleAssessment extends Assessment { * @param {number} config.scores.bad The score to return if the text does not have a title. * @param {string} config.urlTitle The URL to the article about this assessment. * @param {string} config.urlCallToAction The URL to the help article for this assessment. - * @param {function} config.callbacks.getResultText The function that returns the result text. + * @param {function} config.callbacks.getResultTexts The function that returns the result texts. * * @returns {void} */ @@ -57,7 +57,7 @@ export default class TextTitleAssessment extends Assessment { /** * Gets the title from the Paper and based on this returns an assessment result with score. * - * @param {Paper} paper The paper to use for the assessment. + * @param {Paper} paper The paper to use for the assessment. * * @returns {AssessmentResult} The assessment result. */ @@ -97,7 +97,7 @@ export default class TextTitleAssessment extends Assessment { /** * Gets the feedback strings for the text title assessment. - * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultText`. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. * The callback function should return an object with the following properties: * - good: string * - bad: string @@ -105,14 +105,18 @@ export default class TextTitleAssessment extends Assessment { * @returns {{good: string, bad: string}} The feedback strings. */ getFeedbackStrings() { - if ( ! this._config.callbacks.getResultText ) { - return { + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { good: "%1$sTitle%2$s: Your page has a title. Well done!", bad: "%1$sTitle%3$s: Your page does not have a title yet. %2$sAdd one%3$s!", }; + return mapValues( + defaultResultTexts, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); } - return this._config.callbacks.getResultText( { + return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction, } ); From 87896f0bd3c4a9b818824c397f04265414419c11 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 16:29:35 +0200 Subject: [PATCH 11/24] Remove unused config and set the default `assessVariants` and `shouldShowEditButton` to false --- .../src/scoring/assessments/seo/ProductSKUAssessment.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index 8bc482f8a61..84a1278e51a 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -18,7 +18,7 @@ export default class ProductSKUAssessment extends Assessment { * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. * @param {boolean} [config.assessVariants] Whether to assess variants. - * @param {boolean} [config.addSKULocation] Whether to add the SKU location to the assessment result. + * @param {boolean} [config.shouldShowEditButton] Whether to show edit button. * @param {string} [config.editFieldName] The name of the field to edit. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * @@ -34,8 +34,8 @@ export default class ProductSKUAssessment extends Assessment { }, urlTitle: "https://yoa.st/4lw", urlCallToAction: "https://yoa.st/4lx", - assessVariants: true, - addSKULocation: false, + assessVariants: false, + shouldShowEditButton: false, editFieldName: "SKU", }; From 8f983723c138c14c056fb34133e11ffc38ac7ac7 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 16:31:29 +0200 Subject: [PATCH 12/24] Remove the Product identifiers assessment from the product assessors --- .../assessors/productPages/cornerstone/seoAssessor.js | 8 -------- .../src/scoring/assessors/productPages/seoAssessor.js | 8 -------- 2 files changed, 16 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessors/productPages/cornerstone/seoAssessor.js b/packages/yoastseo/src/scoring/assessors/productPages/cornerstone/seoAssessor.js index 7ed8bfecf5c..f8715336c84 100644 --- a/packages/yoastseo/src/scoring/assessors/productPages/cornerstone/seoAssessor.js +++ b/packages/yoastseo/src/scoring/assessors/productPages/cornerstone/seoAssessor.js @@ -17,7 +17,6 @@ import FunctionWordsInKeyphraseAssessment from "../../../assessments/seo/Functio import SingleH1Assessment from "../../../assessments/seo/SingleH1Assessment.js"; import ImageCountAssessment from "../../../assessments/seo/ImageCountAssessment.js"; import ImageKeyphraseAssessment from "../../../assessments/seo/KeyphraseInImageTextAssessment.js"; -import ProductIdentifiersAssessment from "../../../assessments/seo/ProductIdentifiersAssessment.js"; import { createAnchorOpeningTag } from "../../../../helpers"; @@ -131,13 +130,6 @@ const ProductCornerstoneSEOAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.imageKeyphraseUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.imageKeyphraseCTAUrl ), } ), - new ProductIdentifiersAssessment( { - urlTitle: createAnchorOpeningTag( options.productIdentifierUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.productIdentifierCTAUrl ), - assessVariants: options.assessVariants, - productIdentifierOrBarcode: options.productIdentifierOrBarcode, - shouldShowEditButton: options.shouldShowEditButtons, - } ), ]; }; diff --git a/packages/yoastseo/src/scoring/assessors/productPages/seoAssessor.js b/packages/yoastseo/src/scoring/assessors/productPages/seoAssessor.js index 6da441980c7..90d2dc35005 100644 --- a/packages/yoastseo/src/scoring/assessors/productPages/seoAssessor.js +++ b/packages/yoastseo/src/scoring/assessors/productPages/seoAssessor.js @@ -16,7 +16,6 @@ import PageTitleWidthAssessment from "../../assessments/seo/PageTitleWidthAssess import SlugKeywordAssessment from "../../assessments/seo/UrlKeywordAssessment.js"; import SingleH1Assessment from "../../assessments/seo/SingleH1Assessment.js"; import ImageCountAssessment from "../../assessments/seo/ImageCountAssessment.js"; -import ProductIdentifiersAssessment from "../../assessments/seo/ProductIdentifiersAssessment.js"; import { createAnchorOpeningTag } from "../../../helpers"; @@ -111,13 +110,6 @@ const ProductSEOAssessor = function( researcher, options ) { urlTitle: createAnchorOpeningTag( options.imageKeyphraseUrlTitle ), urlCallToAction: createAnchorOpeningTag( options.imageKeyphraseCTAUrl ), } ), - new ProductIdentifiersAssessment( { - urlTitle: createAnchorOpeningTag( options.productIdentifierUrlTitle ), - urlCallToAction: createAnchorOpeningTag( options.productIdentifierCTAUrl ), - assessVariants: options.assessVariants, - productIdentifierOrBarcode: options.productIdentifierOrBarcode, - shouldShowEditButton: options.shouldShowEditButtons, - } ), ]; }; From 99f886b53a6c9cf2af43b806d98a4b12b66ef3d8 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 16:39:09 +0200 Subject: [PATCH 13/24] Extract the translation strings of the Product identifiers assessment result from the assessment --- .../seo/ProductIdentifiersAssessment.js | 144 ++++++++---------- 1 file changed, 61 insertions(+), 83 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js index b2f58662d66..0fe0905b6f4 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js @@ -1,5 +1,4 @@ -import { merge } from "lodash"; -import { __, sprintf } from "@wordpress/i18n"; +import { mapValues, merge } from "lodash"; import Assessment from "../assessment"; import AssessmentResult from "../../../values/AssessmentResult"; import { createAnchorOpeningTag } from "../../../helpers"; @@ -12,6 +11,15 @@ export default class ProductIdentifiersAssessment extends Assessment { * Constructs a product identifier assessment. * * @param {Object} config Potential additional config for the assessment. + * @param {Object} [config.scores] The scores to use for the assessment. + * @param {number} [config.scores.good] The score to return if the product has an identifier. + * @param {number} [config.scores.ok] The score to return if the product doesn't have an identifier. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {boolean} [config.assessVariants] Whether to assess variants. + * @param {boolean} [config.shouldShowEditButton] Whether to show edit button. + * @param {string} [config.editFieldName] The name of the field to edit. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -23,16 +31,17 @@ export default class ProductIdentifiersAssessment extends Assessment { good: 9, ok: 6, }, - urlTitle: createAnchorOpeningTag( "https://yoa.st/4ly" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/4lz" ), - assessVariants: true, - productIdentifierOrBarcode: "Product identifier", - shouldShowEditButton: true, + urlTitle: "https://yoa.st/4ly", + urlCallToAction: "https://yoa.st/4lz", + assessVariants: false, + shouldShowEditButton: false, + editFieldName: "Product identifiers", }; this.identifier = "productIdentifier"; this._config = merge( defaultConfig, config ); - this.name = __( this._config.productIdentifierOrBarcode, "yoast-woo-seo" ); + this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); + this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -56,7 +65,7 @@ export default class ProductIdentifiersAssessment extends Assessment { if ( assessmentResult.getScore() < 9 && this._config.shouldShowEditButton ) { assessmentResult.setHasJumps( true ); - assessmentResult.setEditFieldName( __( "Product identifiers", "yoast-woo-seo" ) ); + assessmentResult.setEditFieldName( this._config.editFieldName ); } return assessmentResult; @@ -102,23 +111,7 @@ export default class ProductIdentifiersAssessment extends Assessment { * or empty object if no score should be returned. */ scoreProductIdentifier( productIdentifierData, config ) { - let feedbackStrings; - - if ( this._config.productIdentifierOrBarcode === "Product identifier" ) { - feedbackStrings = { - okNoVariants: __( "Your product is missing an identifier (like a GTIN code)", "yoast-woo-seo" ), - goodNoVariants: __( "Your product has an identifier", "yoast-woo-seo" ), - okWithVariants: __( "Not all your product variants have an identifier", "yoast-woo-seo" ), - goodWithVariants: __( "All your product variants have an identifier", "yoast-woo-seo" ), - }; - } else { - feedbackStrings = { - okNoVariants: __( "Your product is missing a barcode (like a GTIN code)", "yoast-woo-seo" ), - goodNoVariants: __( "Your product has a barcode", "yoast-woo-seo" ), - okWithVariants: __( "Not all your product variants have a barcode", "yoast-woo-seo" ), - goodWithVariants: __( "All your product variants have a barcode", "yoast-woo-seo" ), - }; - } + const { good, okay } = this.getFeedbackStrings(); // Apply the following scoring conditions to products without variants. if ( [ "simple", "grouped", "external" ].includes( productIdentifierData.productType ) || @@ -126,40 +119,13 @@ export default class ProductIdentifiersAssessment extends Assessment { if ( ! productIdentifierData.hasGlobalIdentifier ) { return { score: config.scores.ok, - text: sprintf( - /* translators: %1$s and %4$s expand to links on yoast.com, %5$s expands to the anchor end tag, - * %2$s expands to the string "Barcode" or "Product identifier", %3$s expands to the feedback string - * "Your product is missing a product identifier (like a GTIN code)" - * or "Your product is missing a barcode (like a GTIN code)" */ - __( - "%1$s%2$s%5$s: %3$s. %4$sInclude it if you can, as it " + - "will help search engines to better understand your content.%5$s", - "yoast-woo-seo" - ), - this._config.urlTitle, - this.name, - feedbackStrings.okNoVariants, - this._config.urlCallToAction, - "" - ), + text: okay.withoutVariants, }; } return { score: config.scores.good, - text: sprintf( - /* translators: %1$s expands to a link on yoast.com, %4$s expands to the anchor end tag, - * %2$s expands to the string "Barcode" or "Product identifier", %3$s expands to the feedback string - * "Your product has a product identifier" or "Your product has a barcode" */ - __( - "%1$s%2$s%4$s: %3$s. Good job!", - "yoast-woo-seo" - ), - this._config.urlTitle, - this.name, - feedbackStrings.goodNoVariants, - "" - ), + text: good.withoutVariants, }; } else if ( productIdentifierData.productType === "variable" && productIdentifierData.hasVariants ) { if ( ! productIdentifierData.doAllVariantsHaveIdentifier ) { @@ -167,40 +133,52 @@ export default class ProductIdentifiersAssessment extends Assessment { // If all variants have an identifier, return green bullet. return { score: config.scores.ok, - text: sprintf( - /* translators: %1$s and %4$s expand to links on yoast.com, %5$s expands to the anchor end tag, - * %2$s expands to the string "Barcode" or "Product identifier", %3$s expands to the string - * "Not all your product variants have a product identifier" - * or "Not all your product variants have a barcode" */ - __( - "%1$s%2$s%5$s: %3$s. %4$sInclude it if you can, as it will help search engines to better understand your content.%5$s", - "yoast-woo-seo" - ), - this._config.urlTitle, - this.name, - feedbackStrings.okWithVariants, - this._config.urlCallToAction, - "" - ), + text: okay.withVariants, }; } return { score: config.scores.good, - text: sprintf( - /* translators: %1$s expands to a link on yoast.com, %4$s expands to the anchor end tag, - * %2$s expands to the string "Barcode" or "Product identifier" , %3$s expands to the feedback string - * "All your product variants have a product identifier" or "All your product variants have a barcode" */ - __( - "%1$s%2$s%4$s: %3$s. Good job!", - "yoast-woo-seo" - ), - this._config.urlTitle, - this.name, - feedbackStrings.goodWithVariants, - "" - ), + text: good.withVariants, }; } return {}; } + + /** + * Gets the feedback strings for the assessment. + * If you want to override the feedback strings, you can do so by providing a custom callback in the config: `this._config.callbacks.getResultTexts`. + * The callback function should return an object with the following properties: + * - good: {withoutVariants: string, withVariants: string} + * - okay: {withoutVariants: string, withVariants: string} + * + * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. + */ + getFeedbackStrings() { + if ( ! this._config.callbacks.getResultTexts ) { + const defaultResultTexts = { + good: { + withoutVariants: "%1$sProduct identifier%3$s: Your product has an identifier. Good job!", + withVariants: "%1$sProduct identifier%3$s: All your product variants have an identifier. Good job!", + }, + okay: { + withoutVariants: "%1$Product identifier%3$s: Your product is missing an identifier (like a GTIN code). %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + withVariants: "%1$sProduct identifier%3$s: Not all your product variants have an identifier. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + }, + }; + defaultResultTexts.good = mapValues( + defaultResultTexts.good, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); + defaultResultTexts.okay = mapValues( + defaultResultTexts.okay, + ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ); + return defaultResultTexts; + } + + return this._config.callbacks.getResultTexts( { + urlTitle: this._config.urlTitle, + urlCallToAction: this._config.urlCallToAction, + } ); + } } From 59f0b84d6a02792ad8e5bb736e2408885c6aec22 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Mon, 2 Sep 2024 17:53:42 +0200 Subject: [PATCH 14/24] Rename variables to be more precise --- .../assessments/readability/ListAssessment.js | 13 ++++++++----- .../readability/TextAlignmentAssessment.js | 15 ++++++++++----- .../readability/WordComplexityAssessment.js | 15 ++++++++------- .../assessments/seo/ImageAltTagsAssessment.js | 14 ++++++++------ .../seo/KeyphraseDistributionAssessment.js | 13 +++++++------ .../seo/ProductIdentifiersAssessment.js | 15 +++++++++------ .../assessments/seo/ProductSKUAssessment.js | 15 +++++++++------ .../assessments/seo/TextTitleAssessment.js | 13 ++++++++----- 8 files changed, 67 insertions(+), 46 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js index 06faff1174a..7121b1ea284 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js @@ -35,8 +35,6 @@ export default class ListAssessment extends Assessment { }; this._config = merge( defaultConfig, config ); - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); this.identifier = "listsPresence"; } @@ -119,6 +117,11 @@ export default class ListAssessment extends Assessment { * @returns {{good: string, bad: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: "%1$sLists%3$s: There is at least one list on this page. Great!", @@ -126,13 +129,13 @@ export default class ListAssessment extends Assessment { }; return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, } ); } } diff --git a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js index a931a7b52e0..4227e684eba 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js @@ -27,8 +27,8 @@ export default class TextAlignmentAssessment extends Assessment { super(); const defaultConfig = { - urlTitle: createAnchorOpeningTag( "https://yoa.st/assessment-alignment" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/assessment-alignment-cta" ), + urlTitle: "https://yoa.st/assessment-alignment", + urlCallToAction: "https://yoa.st/assessment-alignment-cta", scores: { bad: 2, }, @@ -148,6 +148,11 @@ export default class TextAlignmentAssessment extends Assessment { * @returns {{leftToRight: string, rightToLeft: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { rightToLeft: "%1$sAlignment%3$s: There are long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", @@ -159,13 +164,13 @@ export default class TextAlignmentAssessment extends Assessment { } return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, numberOfLongCenterAlignedTexts: this.numberOfLongCenterAlignedTexts, } ); } diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index 513087a7eea..8264f6cfb99 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -37,10 +37,6 @@ export default class WordComplexityAssessment extends Assessment { this.identifier = "wordComplexity"; this._config = merge( defaultConfig, config ); - - // Creates an anchor opening tag for the shortlinks. - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -97,6 +93,11 @@ export default class WordComplexityAssessment extends Assessment { * @returns {{acceptableAmount: string, goodAmount: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { acceptableAmount: "%1$sWord complexity%3$s: Some words in your text are considered complex. %2$sTry to use shorter and more familiar words to improve readability%3$s.", @@ -104,14 +105,14 @@ export default class WordComplexityAssessment extends Assessment { }; return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } const complexWordsPercentage = this._wordComplexity.percentage; return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, complexWordsPercentage, } ); } diff --git a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js index 868fc1aa320..9af65bec464 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js @@ -34,9 +34,6 @@ export default class ImageAltTagsAssessment extends Assessment { this.identifier = "imageAltTags"; this._config = merge( defaultConfig, config ); - - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -117,6 +114,11 @@ export default class ImageAltTagsAssessment extends Assessment { * @returns {{good: string, noneHasAltBad: string, someHaveAltBad: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: "%1$sImage alt tags%3$s: All images have alt attributes. Good job!", @@ -128,13 +130,13 @@ export default class ImageAltTagsAssessment extends Assessment { } return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, numberOfImagesWithoutAlt: this.altTagsProperties.noAlt, totalNumberOfImages: this.imageCount, } ); diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index afcfbde7a26..904adbcabfe 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -49,10 +49,6 @@ class KeyphraseDistributionAssessment extends Assessment { this.identifier = "keyphraseDistribution"; this._config = merge( defaultConfig, config ); - - // Creates an anchor opening tag for the shortlinks. - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -139,6 +135,11 @@ class KeyphraseDistributionAssessment extends Assessment { * @returns {{good: string, okay: string, bad: string, consideration: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: "%1$sKeyphrase distribution%3$s: Good job!", @@ -148,11 +149,11 @@ class KeyphraseDistributionAssessment extends Assessment { }; return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } - return this._config.callbacks.getResultTexts( { urlTitle: this._config.urlTitle, urlCallToAction: this._config.urlCallToAction } ); + return this._config.callbacks.getResultTexts( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag } ); } /** diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js index 0fe0905b6f4..e31ca41a610 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js @@ -40,8 +40,6 @@ export default class ProductIdentifiersAssessment extends Assessment { this.identifier = "productIdentifier"; this._config = merge( defaultConfig, config ); - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -154,6 +152,11 @@ export default class ProductIdentifiersAssessment extends Assessment { * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: { @@ -167,18 +170,18 @@ export default class ProductIdentifiersAssessment extends Assessment { }; defaultResultTexts.good = mapValues( defaultResultTexts.good, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); defaultResultTexts.okay = mapValues( defaultResultTexts.okay, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); return defaultResultTexts; } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, } ); } } diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index 84a1278e51a..e9ebaf3e8eb 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -41,8 +41,6 @@ export default class ProductSKUAssessment extends Assessment { this.identifier = "productSKU"; this._config = merge( defaultConfig, config ); - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -157,6 +155,11 @@ export default class ProductSKUAssessment extends Assessment { * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: { @@ -170,18 +173,18 @@ export default class ProductSKUAssessment extends Assessment { }; defaultResultTexts.good = mapValues( defaultResultTexts.good, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); defaultResultTexts.okay = mapValues( defaultResultTexts.okay, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); return defaultResultTexts; } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, } ); } } diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 948f18d8150..4d24112d3d4 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -35,8 +35,6 @@ export default class TextTitleAssessment extends Assessment { this.identifier = "textTitleAssessment"; this._config = merge( defaultConfig, config ); - this._config.urlTitle = createAnchorOpeningTag( this._config.urlTitle ); - this._config.urlCallToAction = createAnchorOpeningTag( this._config.urlCallToAction ); } /** @@ -105,6 +103,11 @@ export default class TextTitleAssessment extends Assessment { * @returns {{good: string, bad: string}} The feedback strings. */ getFeedbackStrings() { + // `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment. + const urlTitleAnchorOpeningTag = createAnchorOpeningTag( this._config.urlTitle ); + // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. + const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: "%1$sTitle%2$s: Your page has a title. Well done!", @@ -112,13 +115,13 @@ export default class TextTitleAssessment extends Assessment { }; return mapValues( defaultResultTexts, - ( resultText ) => this.formatResultText( resultText, this._config.urlTitle, this._config.urlCallToAction ) + ( resultText ) => this.formatResultText( resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag ) ); } return this._config.callbacks.getResultTexts( { - urlTitle: this._config.urlTitle, - urlCallToAction: this._config.urlCallToAction, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, } ); } } From ad644425d9afce8d072874135dd6a61310003147 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 3 Sep 2024 14:43:23 +0200 Subject: [PATCH 15/24] Add unit test --- .../spec/scoring/assessments/assessmentSpec.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/yoastseo/spec/scoring/assessments/assessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/assessmentSpec.js index 3678698a64d..d612704f320 100644 --- a/packages/yoastseo/spec/scoring/assessments/assessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/assessmentSpec.js @@ -65,3 +65,14 @@ describe( "test hasEnoughContentForAssessment", () => { } ); } ); +describe( "test formatResultText", () => { + it( "should return a formatted string", () => { + const mockAssessment = new Assessment(); + const resultText = "This is a test string with a %1$s and a %2$s"; + const urlTitle = "www.example.com"; + const urlCallToAction = "www.example2.com"; + + expect( mockAssessment.formatResultText( resultText, urlTitle, urlCallToAction ) ).toBe( "This is a test string with a www.example.com and a www.example2.com" ); + } ); +} ); + From faed5ba29d6ed5ca6d1411a3751077cd89936476 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 3 Sep 2024 14:43:50 +0200 Subject: [PATCH 16/24] Add default value for this._config.callbacks --- .../assessments/readability/ListAssessment.js | 2 ++ .../readability/TextAlignmentAssessment.js | 2 ++ .../readability/WordComplexityAssessment.js | 2 ++ .../assessments/seo/ImageAltTagsAssessment.js | 2 ++ .../seo/KeyphraseDistributionAssessment.js | 4 +++- .../seo/ProductIdentifiersAssessment.js | 2 ++ .../assessments/seo/ProductSKUAssessment.js | 2 ++ .../scoring/assessments/seo/TextTitleAssessment.js | 14 ++++++++------ 8 files changed, 23 insertions(+), 7 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js index 7121b1ea284..6de242e0d5a 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ListAssessment.js @@ -18,6 +18,7 @@ export default class ListAssessment extends Assessment { * @param {object} [config.scores] The scores to use for the assessment. * @param {number} [config.scores.bad] The score to return if the text has no list. * @param {number} [config.scores.good] The score to return if the text has a list. + * @param {object} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -32,6 +33,7 @@ export default class ListAssessment extends Assessment { bad: 3, good: 9, }, + callbacks: {}, }; this._config = merge( defaultConfig, config ); diff --git a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js index 4227e684eba..77a935074bc 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/TextAlignmentAssessment.js @@ -19,6 +19,7 @@ export default class TextAlignmentAssessment extends Assessment { * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. * @param {object} [config.scores] The scores to use for the assessment. * @param {number} [config.scores.bad] The score to return if the text has an over-use of center-alignment. + * @param {object} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -32,6 +33,7 @@ export default class TextAlignmentAssessment extends Assessment { scores: { bad: 2, }, + callbacks: {}, }; this._config = merge( defaultConfig, config ); diff --git a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js index 8264f6cfb99..8d6cbc36954 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/WordComplexityAssessment.js @@ -19,6 +19,7 @@ export default class WordComplexityAssessment extends Assessment { * @param {number} [config.scores.goodAmount] The score to return if the text has a good amount of complex words. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {object} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -33,6 +34,7 @@ export default class WordComplexityAssessment extends Assessment { }, urlTitle: "https://yoa.st/4ls", urlCallToAction: "https://yoa.st/4lt", + callbacks: {}, }; this.identifier = "wordComplexity"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js index 9af65bec464..88c02ac5365 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js @@ -16,6 +16,7 @@ export default class ImageAltTagsAssessment extends Assessment { * @param {number} [config.scores.good] The score to return if all images have alt tags. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {object} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -30,6 +31,7 @@ export default class ImageAltTagsAssessment extends Assessment { }, urlTitle: "", urlCallToAction: "", + callbacks: {}, }; this.identifier = "imageAltTags"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js index 904adbcabfe..7627dd50a90 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/KeyphraseDistributionAssessment.js @@ -25,7 +25,8 @@ class KeyphraseDistributionAssessment extends Assessment { * @param {number} [config.scores.consideration] The score to return if there are no keyword occurrences. * @param {string} [config.urlTitle] The URL to the article about this assessment. * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. - * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. + * @param {object} [config.callbacks] The callbacks to use for the assessment. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -45,6 +46,7 @@ class KeyphraseDistributionAssessment extends Assessment { }, urlTitle: "https://yoa.st/33q", urlCallToAction: "https://yoa.st/33u", + callbacks: {}, }; this.identifier = "keyphraseDistribution"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js index e31ca41a610..95ee1db595d 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js @@ -19,6 +19,7 @@ export default class ProductIdentifiersAssessment extends Assessment { * @param {boolean} [config.assessVariants] Whether to assess variants. * @param {boolean} [config.shouldShowEditButton] Whether to show edit button. * @param {string} [config.editFieldName] The name of the field to edit. + * @param {function} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -36,6 +37,7 @@ export default class ProductIdentifiersAssessment extends Assessment { assessVariants: false, shouldShowEditButton: false, editFieldName: "Product identifiers", + callbacks: {}, }; this.identifier = "productIdentifier"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index e9ebaf3e8eb..b55b72fd09c 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -20,6 +20,7 @@ export default class ProductSKUAssessment extends Assessment { * @param {boolean} [config.assessVariants] Whether to assess variants. * @param {boolean} [config.shouldShowEditButton] Whether to show edit button. * @param {string} [config.editFieldName] The name of the field to edit. + * @param {object} [config.callbacks] The callbacks to use for the assessment. * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} @@ -37,6 +38,7 @@ export default class ProductSKUAssessment extends Assessment { assessVariants: false, shouldShowEditButton: false, editFieldName: "SKU", + callbacks: {}, }; this.identifier = "productSKU"; diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 4d24112d3d4..259d901d5a4 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -13,12 +13,13 @@ export default class TextTitleAssessment extends Assessment { * Constructs a text title assessment. * * @param {object} config The config to use for the assessment. - * @param {object} config.scores The scores to use for the assessment. - * @param {number} config.scores.good The score to return if the text has a title. - * @param {number} config.scores.bad The score to return if the text does not have a title. - * @param {string} config.urlTitle The URL to the article about this assessment. - * @param {string} config.urlCallToAction The URL to the help article for this assessment. - * @param {function} config.callbacks.getResultTexts The function that returns the result texts. + * @param {object} [config.scores] The scores to use for the assessment. + * @param {number} [config.scores.good] The score to return if the text has a title. + * @param {number} [config.scores.bad] The score to return if the text doesn't have a title. + * @param {string} [config.urlTitle] The URL to the article about this assessment. + * @param {string} [config.urlCallToAction] The URL to the help article for this assessment. + * @param {object} [config.callbacks] The callbacks to use for the assessment. + * @param {function} [config.callbacks.getResultTexts] The function that returns the result texts. * * @returns {void} */ @@ -31,6 +32,7 @@ export default class TextTitleAssessment extends Assessment { }, urlTitle: "https://yoa.st/4nh", urlCallToAction: "https://yoa.st/4ni", + callbacks: {}, }; this.identifier = "textTitleAssessment"; From 3369a923fa3d180d03c9461c2a8dfc9b59d75d2c Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 3 Sep 2024 16:57:50 +0200 Subject: [PATCH 17/24] Fix typos in feedback strings --- .../src/scoring/assessments/seo/ImageAltTagsAssessment.js | 8 +++++--- .../assessments/seo/ProductIdentifiersAssessment.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js index 88c02ac5365..912a4da31c6 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ImageAltTagsAssessment.js @@ -121,14 +121,16 @@ export default class ImageAltTagsAssessment extends Assessment { // `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action. const urlActionAnchorOpeningTag = createAnchorOpeningTag( this._config.urlCallToAction ); + const numberOfImagesWithoutAlt = this.altTagsProperties.noAlt; + if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { good: "%1$sImage alt tags%3$s: All images have alt attributes. Good job!", noneHasAltBad: "%1$sImage alt tags%3$s: None of the images has alt attributes. %2$sAdd alt attributes to your images%3$s!", someHaveAltBad: "%1$sImage alt tags%3$s: Some images don't have alt attributes. %2$sAdd alt attributes to your images%3$s!", }; - if ( this.imageCount === 1 ) { - defaultResultTexts.someHaveAltBad = "%1$sImage alt tags%3$s: One image doesn't have alt attributes. %2$sAdd alt attributes to your images%2$s!"; + if ( numberOfImagesWithoutAlt === 1 ) { + defaultResultTexts.someHaveAltBad = "%1$sImage alt tags%3$s: One image doesn't have alt attributes. %2$sAdd alt attributes to your images%3$s!"; } return mapValues( defaultResultTexts, @@ -139,7 +141,7 @@ export default class ImageAltTagsAssessment extends Assessment { return this._config.callbacks.getResultTexts( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag, - numberOfImagesWithoutAlt: this.altTagsProperties.noAlt, + numberOfImagesWithoutAlt, totalNumberOfImages: this.imageCount, } ); } diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js index 95ee1db595d..68e76ab6e3d 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js @@ -166,7 +166,7 @@ export default class ProductIdentifiersAssessment extends Assessment { withVariants: "%1$sProduct identifier%3$s: All your product variants have an identifier. Good job!", }, okay: { - withoutVariants: "%1$Product identifier%3$s: Your product is missing an identifier (like a GTIN code). %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + withoutVariants: "%1$sProduct identifier%3$s: Your product is missing an identifier (like a GTIN code). %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", withVariants: "%1$sProduct identifier%3$s: Not all your product variants have an identifier. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", }, }; From f1d15fafa5b98f721bc353d73296c0281e0efb6e Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Tue, 3 Sep 2024 16:59:01 +0200 Subject: [PATCH 18/24] Adjust and add unit tests --- .../seo/ImageAltTagsAssessmentSpec.js | 117 +++++++++++++++--- .../seo/ProductIdentifiersAssessmentSpec.js | 94 ++++++++++++-- .../seo/ProductSKUAssessmentSpec.js | 79 +++++++++++- 3 files changed, 261 insertions(+), 29 deletions(-) diff --git a/packages/yoastseo/spec/scoring/assessments/seo/ImageAltTagsAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/ImageAltTagsAssessmentSpec.js index 493f0867980..89d37bd4edc 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/ImageAltTagsAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/ImageAltTagsAssessmentSpec.js @@ -1,3 +1,4 @@ +import { __, _n, sprintf } from "@wordpress/i18n"; import ImageAltTagsAssessment from "../../../../src/scoring/assessments/seo/ImageAltTagsAssessment"; import Paper from "../../../../src/values/Paper.js"; import Factory from "../../../../src/helpers/factory.js"; @@ -8,7 +9,7 @@ describe( "test to check if all images have alt tags", function() { it( "assesses text with 4 images and none of them has alt tags", function() { const mockPaper = new Paper( "sample" ); - const assessment = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { + const result = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { imageCount: 4, altTagCount: { noAlt: 4, @@ -16,15 +17,14 @@ describe( "test to check if all images have alt tags", function() { }, }, true ) ); - expect( assessment.getScore() ).toEqual( 3 ); - expect( assessment.getText() ).toEqual( "Image alt tags: None of the images " + - "has alt attributes. Add alt attributes to your images!" ); + expect( result.getScore() ).toEqual( 3 ); + expect( result.getText() ).toEqual( "Image alt tags: None of the images has alt attributes. Add alt attributes to your images!" ); } ); it( "assesses text with 4 images and 1 of the doesn't have alt tags", function() { const mockPaper = new Paper( "sample" ); - const assessment = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { + const result = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { imageCount: 4, altTagCount: { noAlt: 1, @@ -32,15 +32,14 @@ describe( "test to check if all images have alt tags", function() { }, }, true ) ); - expect( assessment.getScore() ).toEqual( 3 ); - expect( assessment.getText() ).toEqual( "Image alt tags: 1 image out of 4 " + - "doesn't have alt attributes. Add alt attributes to your images!" ); + expect( result.getScore() ).toEqual( 3 ); + expect( result.getText() ).toEqual( "Image alt tags: One image doesn't have alt attributes. Add alt attributes to your images!" ); } ); it( "assesses text with 4 images and 2 of the doesn't have alt tags", function() { const mockPaper = new Paper( "These are just five words " ); - const assessment = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { + const result = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { imageCount: 4, altTagCount: { noAlt: 2, @@ -48,15 +47,14 @@ describe( "test to check if all images have alt tags", function() { }, }, true ) ); - expect( assessment.getScore() ).toEqual( 3 ); - expect( assessment.getText() ).toEqual( "Image alt tags: 2 images out of 4 " + - "don't have alt attributes. Add alt attributes to your images!" ); + expect( result.getScore() ).toEqual( 3 ); + expect( result.getText() ).toEqual( "Image alt tags: Some images don't have alt attributes. Add alt attributes to your images!" ); } ); it( "assesses a text with 4 images and all of them have alt attributes", function() { const mockPaper = new Paper( "These are just five words . " ); - const assessment = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { + const result = imageAltTagsAssessment.getResult( mockPaper, Factory.buildMockResearcher( { imageCount: 4, altTagCount: { noAlt: 0, @@ -64,8 +62,8 @@ describe( "test to check if all images have alt tags", function() { }, }, true ) ); - expect( assessment.getScore() ).toEqual( 9 ); - expect( assessment.getText() ).toEqual( "Image alt tags: All images have alt attributes. Good job!" ); + expect( result.getScore() ).toEqual( 9 ); + expect( result.getText() ).toEqual( "Image alt tags: All images have alt attributes. Good job!" ); } ); } ); @@ -94,3 +92,92 @@ describe( "tests for the assessment applicability.", function() { }, true ) ) ).toBe( true ); } ); } ); + +describe( "tests for retrieving the feedback strings.", function() { + it( "should return the default feedback strings when no custom callback is provided.", function() { + const assessment = new ImageAltTagsAssessment(); + const mockPaper = new Paper( "These are just five words . " ); + + assessment.getResult( mockPaper, Factory.buildMockResearcher( { + imageCount: 4, + altTagCount: { + noAlt: 0, + withAlt: 4, + }, + }, true ) ); + + expect( assessment.getFeedbackStrings() ).toEqual( { + good: "Image alt tags: All images have alt attributes. Good job!", + noneHasAltBad: "Image alt tags: None of the images has alt attributes. Add alt attributes to your images!", + someHaveAltBad: "Image alt tags: Some images don't have alt attributes. Add alt attributes to your images!", + } ); + } ); + + it( "should return the custom feedback strings when a custom callback is provided.", function() { + /** + * Returns the result texts for the Image alt tags assessment. + * + * @param {string} urlTitleAnchorOpeningTag The anchor opening tag to the article about this assessment. + * @param {string} urlActionAnchorOpeningTag The anchor opening tag to the call to action URL to the help article of this assessment. + * @param {number} numberOfImagesWithoutAlt The number of images without alt tags. + * @param {number} totalNumberOfImages The total number of images found in the text. + * + * @returns {{noneHasAltBad: string, good: string, someHaveAltBad: string}} The object that contains the result texts as a translation string. + */ + const getResultTexts = ( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag, numberOfImagesWithoutAlt, totalNumberOfImages } ) => { + return { + good: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. */ + __( + "%1$sImage alt tags%2$s: All images have alt attributes. Good job!", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + "" + ), + noneHasAltBad: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag */ + __( + "%1$sImage alt tags%3$s: None of the images has alt attributes. %2$sAdd alt attributes to your images%3$s!", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + someHaveAltBad: sprintf( + /* translators: %3$s and %4$s expand to links on yoast.com, %5$s expands to the anchor end tag, %1$d expands to the number of images without alt tags, %2$d expands to the number of images found in the text, */ + _n( + "%3$sImage alt tags%5$s: %1$d image out of %2$d doesn't have alt attributes. %4$sAdd alt attributes to your images%5$s!", + "%3$sImage alt tags%5$s: %1$d images out of %2$d don't have alt attributes. %4$sAdd alt attributes to your images%5$s!", + numberOfImagesWithoutAlt, + "yoast-woo-seo" + ), + numberOfImagesWithoutAlt, + totalNumberOfImages, + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + }; + }; + const assessment = new ImageAltTagsAssessment( { + callbacks: { getResultTexts }, + } ); + const mockPaper = new Paper( "These are just five words . " ); + + assessment.getResult( mockPaper, Factory.buildMockResearcher( { + imageCount: 4, + altTagCount: { + noAlt: 0, + withAlt: 4, + }, + }, true ) ); + + expect( assessment.getFeedbackStrings() ).toEqual( { + good: "Image alt tags: All images have alt attributes. Good job!", + noneHasAltBad: "Image alt tags: None of the images has alt attributes. Add alt attributes to your images!", + someHaveAltBad: "Image alt tags: 0 images out of 4 don't have alt attributes. Add alt attributes to your images!", + } ); + } ); +} ); diff --git a/packages/yoastseo/spec/scoring/assessments/seo/ProductIdentifiersAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/ProductIdentifiersAssessmentSpec.js index 984d61549ab..7d05175a209 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/ProductIdentifiersAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/ProductIdentifiersAssessmentSpec.js @@ -1,4 +1,4 @@ -import { createAnchorOpeningTag } from "../../../../src/helpers"; +import { __, sprintf } from "@wordpress/i18n"; import ProductIdentifiersAssessment from "../../../../src/scoring/assessments/seo/ProductIdentifiersAssessment"; import Paper from "../../../../src/values/Paper"; @@ -6,7 +6,7 @@ const paper = new Paper( "" ); describe( "a test for Product identifiers assessment for WooCommerce", function() { - const assessment = new ProductIdentifiersAssessment( { assessVariants: true } ); + const assessment = new ProductIdentifiersAssessment( { assessVariants: true, shouldShowEditButton: true } ); it( "returns the score 9 when a product has a global identifier and no variants", function() { const customData = { @@ -126,7 +126,6 @@ describe( "a test for Product identifiers assessment for WooCommerce", function( " it if you can, as it will help search engines to better understand your content." ); } ); - it( "returns the score 9 with the feedback for a simple product when a variable product has no variants but has a global identifier", function() { const customData = { hasGlobalIdentifier: true, @@ -160,13 +159,80 @@ describe( "a test for Product identifiers assessment for WooCommerce", function( " Include" + " it if you can, as it will help search engines to better understand your content." ); } ); + + it( "returns `hasJump` as true when `shouldEditButton` is set to true and the score is less than 9", function() { + const customData = { + hasGlobalIdentifier: true, + hasVariants: true, + doAllVariantsHaveIdentifier: false, + productType: "variable", + }; + + const paperWithCustomData = new Paper( "", { customData } ); + const assessmentResult = assessment.getResult( paperWithCustomData ); + + expect( assessmentResult.hasJumps() ).toBeTruthy(); + } ); } ); describe( "a test for Product identifiers assessment for Shopify", () => { - const assessment = new ProductIdentifiersAssessment( { urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify81" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify82" ), - assessVariants: false, - productIdentifierOrBarcode: "Barcode" } ); + /** + * Returns the result texts for the Barcode assessment. + * @param {string} urlTitleAnchorOpeningTag The anchor opening tag to the article about this assessment. + * @param {string} urlActionAnchorOpeningTag The anchor opening tag to the call to action URL to the help article of this assessment. + * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. + */ + const getResultTexts = ( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag } ) => { + return { + good: { + withoutVariants: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag */ + __( + "%1$sBarcode%2$s: Your product has a barcode. Good job!", + "shopify-seo" + ), + urlTitleAnchorOpeningTag, + "" + ), + withVariants: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag */ + __( + "%1$sBarcode%2$s: All your product variants have a barcode. Good job!", + "shopify-seo" + ), + urlTitleAnchorOpeningTag, + "" + ), + }, + okay: { + withoutVariants: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag */ + __( + "%1$sBarcode%3$s: Your product is missing a barcode (like a GTIN code). %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + "shopify-seo" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + withVariants: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag */ + __( + "%1$sBarcode%3$s: Not all your product variants have a barcode. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + "shopify-seo" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + }, + }; + }; + const assessment = new ProductIdentifiersAssessment( { + urlTitle: "https://yoa.st/shopify81", + urlCallToAction: "https://yoa.st/shopify82", + callbacks: { getResultTexts }, + } ); it( "returns with score 9 when the product has global identifier and no variants", () => { const customData = { @@ -185,7 +251,6 @@ describe( "a test for Product identifiers assessment for Shopify", () => { it( "returns with score 6 when the product doesn't have a global identifier nor variants", () => { const customData = { - hasGlobalIdentifier: false, hasVariants: false, productType: "simple", @@ -199,6 +264,19 @@ describe( "a test for Product identifiers assessment for Shopify", () => { " Your product is missing a barcode (like a GTIN code). Include" + " it if you can, as it will help search engines to better understand your content." ); } ); + + it( "returns `hasJumps` as false for shopify, since the `shouldEditButton` is set to false even though the score is less than 9", () => { + const customData = { + hasGlobalIdentifier: false, + hasVariants: false, + productType: "simple", + }; + + const paperWithCustomData = new Paper( "", { customData } ); + const assessmentResult = assessment.getResult( paperWithCustomData ); + + expect( assessmentResult.hasJumps() ).toBeFalsy(); + } ); } ); describe( "a test for the applicability of the assessment", function() { diff --git a/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js index 7a73aa790f6..57e40f04dcd 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js @@ -1,10 +1,10 @@ -import { createAnchorOpeningTag } from "../../../../src/helpers"; +import { __, sprintf } from "@wordpress/i18n"; import ProductSKUAssessment from "../../../../src/scoring/assessments/seo/ProductSKUAssessment"; import Paper from "../../../../src/values/Paper"; describe( "a test for SKU assessment for WooCommerce", function() { - const assessment = new ProductSKUAssessment( { assessVariants: true, addSKULocation: true } ); + const assessment = new ProductSKUAssessment( { assessVariants: true, shouldShowEditButton: true } ); it( "returns the score 9 when a product has a global SKU and no variants", function() { const customData = { @@ -153,13 +153,80 @@ describe( "a test for SKU assessment for WooCommerce", function() { "Include it if you can, as it will help search engines to " + "better understand your content." ); } ); + + it( "returns `hasJumps` as true when the score is less than 9 and `shouldShowEditButton` is true", function() { + const customData = { + hasGlobalSKU: false, + hasVariants: false, + doAllVariantsHaveSKU: false, + productType: "simple", + }; + + const paperWithCustomData = new Paper( "", { customData } ); + const assessmentResult = assessment.getResult( paperWithCustomData ); + + expect( assessmentResult.hasJumps() ).toBe( true ); + } ); } ); describe( "a test for SKU assessment for Shopify", () => { - const assessment = new ProductSKUAssessment( { urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify79" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify80" ), - assessVariants: false, - addSKULocation: false, + /** + * Returns the result texts for the Product SKU assessment. + * + * @param {string} urlTitleAnchorOpeningTag The anchor opening tag to the article about this assessment. + * @param {string} urlActionAnchorOpeningTag The anchor opening tag to the call to action URL to the help article of this assessment. + * @returns {{good: {withoutVariants: string, withVariants: string}, okay: {withoutVariants: string, withVariants: string}}} The feedback strings. + */ + const getResultTexts = ( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag } ) => { + return { + good: { + withoutVariants: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. */ + __( + "%1$sSKU%2$s: Your product has a SKU. Good job!", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + "" + ), + withVariants: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag. */ + __( + "%1$sSKU%2$s: All your product variants have a SKU. Good job!", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + "" + ), + }, + okay: { + withoutVariants: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag. */ + __( + "%1$sSKU%3$s: Your product is missing a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + withVariants: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag. */ + __( + "%1$sSKU%3$s: Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product data box. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + "yoast-woo-seo" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "" + ), + }, + }; + }; + const assessment = new ProductSKUAssessment( { + urlTitle: "https://yoa.st/shopify79", + urlCallToAction: "https://yoa.st/shopify80", + callbacks: { getResultTexts }, } ); it( "returns with score 9 when the product has global SKU and no variants", () => { From fb5b18ea76a92c355dc2e2b53fb6112b619c69c5 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 4 Sep 2024 12:03:59 +0200 Subject: [PATCH 19/24] Fix typo in feedback string --- .../yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js index 259d901d5a4..b65d15154d4 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/TextTitleAssessment.js @@ -112,7 +112,7 @@ export default class TextTitleAssessment extends Assessment { if ( ! this._config.callbacks.getResultTexts ) { const defaultResultTexts = { - good: "%1$sTitle%2$s: Your page has a title. Well done!", + good: "%1$sTitle%3$s: Your page has a title. Well done!", bad: "%1$sTitle%3$s: Your page does not have a title yet. %2$sAdd one%3$s!", }; return mapValues( From 2645991be4291f71348a6f8c1ae2e72e2851a291 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 4 Sep 2024 16:08:21 +0200 Subject: [PATCH 20/24] Adapt unit tests --- .../en/englishPaperForPerformanceTest.js | 2 +- .../es/spanishPaperForPerformanceTest.js | 2 +- .../TextAlignmentAssessmentSpec.js | 87 ++++++++++++++++++- .../WordComplexityAssessmentSpec.js | 85 +++++++++++++++++- .../productPages/contentAssessorSpec.js | 60 ++----------- .../cornerstone/contentAssessorSpec.js | 29 ++----- .../cornerstone/seoAssessorSpec.js | 80 ----------------- .../fullTextTests/runFullTextTests.js | 17 ++-- .../testTexts/en/englishPaper1.js | 2 +- .../assessors/productPages/seoAssessorSpec.js | 78 ----------------- .../specHelpers/scoring/seoAssessorTests.js | 4 +- .../seo/ProductIdentifiersAssessment.js | 2 +- 12 files changed, 192 insertions(+), 256 deletions(-) diff --git a/packages/yoastseo/spec/fullTextTests/testTexts/en/englishPaperForPerformanceTest.js b/packages/yoastseo/spec/fullTextTests/testTexts/en/englishPaperForPerformanceTest.js index 48bb33fc8ef..fdd6606787d 100644 --- a/packages/yoastseo/spec/fullTextTests/testTexts/en/englishPaperForPerformanceTest.js +++ b/packages/yoastseo/spec/fullTextTests/testTexts/en/englishPaperForPerformanceTest.js @@ -160,7 +160,7 @@ const expectedResults = { wordComplexity: { isApplicable: true, score: 6, - resultText: "Word complexity: 25.16% of the words in your text are considered complex. " + + resultText: "Word complexity: Some words in your text are considered complex. " + "Try to use shorter and more familiar words to improve readability.", }, textAlignment: { diff --git a/packages/yoastseo/spec/fullTextTests/testTexts/es/spanishPaperForPerformanceTest.js b/packages/yoastseo/spec/fullTextTests/testTexts/es/spanishPaperForPerformanceTest.js index b8b92c27c17..270298eacb7 100644 --- a/packages/yoastseo/spec/fullTextTests/testTexts/es/spanishPaperForPerformanceTest.js +++ b/packages/yoastseo/spec/fullTextTests/testTexts/es/spanishPaperForPerformanceTest.js @@ -160,7 +160,7 @@ const expectedResults = { wordComplexity: { isApplicable: true, score: 6, - resultText: "Word complexity: 25.52% of the words in your text are considered complex." + + resultText: "Word complexity: Some words in your text are considered complex." + " Try to use shorter and more familiar words to improve readability.", }, textAlignment: { diff --git a/packages/yoastseo/spec/scoring/assessments/readability/TextAlignmentAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/TextAlignmentAssessmentSpec.js index 54cb8ea9241..251c9ed2bc0 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/TextAlignmentAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/TextAlignmentAssessmentSpec.js @@ -1,3 +1,4 @@ +import { sprintf, _n } from "@wordpress/i18n"; import Mark from "../../../../src/values/Mark"; import Paper from "../../../../src/values/Paper.js"; import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher"; @@ -61,7 +62,7 @@ describe( "tests assessment results in languages written from left to right (LTR expect( assessmentResult.getScore() ).toBe( 2 ); expect( assessmentResult.getText() ).toBe( "Alignment:" + - " There are 2 long sections of center-aligned text. " + + " There are long sections of center-aligned text. " + "We recommend making them left-aligned." ); expect( assessmentResult.hasMarks() ).toBe( true ); expect( textAlignmentAssessment.getMarks( mockPaperLTR, researcher ) ).toEqual( [ @@ -86,7 +87,7 @@ describe( "tests assessment results in languages written from left to right (LTR expect( assessmentResult.getScore() ).toBe( 2 ); expect( assessmentResult.getText() ).toBe( "Alignment:" + - " There are 2 long sections of center-aligned text. " + + " There are long sections of center-aligned text. " + "We recommend making them left-aligned." ); expect( assessmentResult.hasMarks() ).toBe( true ); expect( textAlignmentAssessment.getMarks( mockPaperLTR, researcher ) ).toEqual( [ @@ -111,7 +112,7 @@ describe( "tests assessment results in languages written from left to right (LTR expect( assessmentResult.getScore() ).toBe( 2 ); expect( assessmentResult.getText() ).toBe( "Alignment:" + - " There are 2 long sections of center-aligned text. " + + " There are long sections of center-aligned text. " + "We recommend making them left-aligned." ); expect( assessmentResult.hasMarks() ).toBe( true ); expect( textAlignmentAssessment.getMarks( mockPaperLTR, researcher ) ).toEqual( [ @@ -190,7 +191,7 @@ describe( "tests the feedback strings of the assessment run for languages writte expect( assessmentResult.getScore() ).toBe( 2 ); expect( assessmentResult.getText() ).toBe( "Alignment: " + - "There are 2 long sections of center-aligned text. " + + "There are long sections of center-aligned text. " + "We recommend making them right-aligned." ); expect( assessmentResult.hasMarks() ).toBe( true ); expect( textAlignmentAssessment.getMarks( mockPaperRTL, researcher ) ).toEqual( [ @@ -208,6 +209,84 @@ describe( "tests the feedback strings of the assessment run for languages writte } ); } ); +describe( "tests for retrieving the feedback strings.", function() { + it( "returns the default strings when no custom `getResultTexts` callback is provided.", function() { + const assessment = new TextAlignmentAssessment(); + expect( assessment.getFeedbackStrings() ).toEqual( { + leftToRight: "Alignment: There are long sections of center-aligned text. We recommend making them left-aligned.", + rightToLeft: "Alignment: There are long sections of center-aligned text. We recommend making them right-aligned.", + } ); + } ); + it( "returns the default strings when no custom `getResultTexts` callback is provided: there is one long section of center-aligned text", function() { + const assessment = new TextAlignmentAssessment(); + const mockPaperLTR = new Paper( "

This is a paragraph with a bit more than fifty characters.

" ); + const mockResearcher = new EnglishResearcher( mockPaperLTR ); + mockResearcher.addResearch( "getLongCenterAlignedTexts", getLongCenterAlignedTexts ); + + assessment.getResult( mockPaperLTR, mockResearcher ); + + expect( assessment.getFeedbackStrings() ).toEqual( { + leftToRight: "Alignment: There is a long section of center-aligned text. We recommend making it left-aligned.", + rightToLeft: "Alignment: There is a long section of center-aligned text. We recommend making it right-aligned.", + } ); + } ); + it( "overrides the default strings when a custom `getResultTexts` callback is provided", function() { + /** + * Returns the result texts for the Text alignment assessment. + * @param {Object} config The configuration object that contains data needed to generate the result text. + * @param {string} config.urlTitleAnchorOpeningTag The anchor opening tag to the article about this assessment. + * @param {string} config.urlActionAnchorOpeningTag The anchor opening tag to the call to action URL to the help article of this assessment. + * @param {number} config.numberOfLongCenterAlignedTexts The number of long center-aligned texts found in the text. + * + * @returns {{rightToLeft: string, leftToRight: string}} The object that contains the result texts as a translation string. + */ + const getResultTexts = ( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag, numberOfLongCenterAlignedTexts } ) => { + return { + rightToLeft: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag, + %4$s expands to the number of the long center-aligned sections in the text */ + _n( + "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it right-aligned%3$s.", + "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them right-aligned%3$s.", + numberOfLongCenterAlignedTexts, + "wordpress-seo-premium" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "", + numberOfLongCenterAlignedTexts + ), + leftToRight: sprintf( + /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag, + %4$s expands to the number of the long center-aligned sections in the text */ + _n( + "%1$sAlignment%3$s: There is a long section of center-aligned text. %2$sWe recommend making it left-aligned%3$s.", + "%1$sAlignment%3$s: There are %4$s long sections of center-aligned text. %2$sWe recommend making them left-aligned%3$s.", + numberOfLongCenterAlignedTexts, + "wordpress-seo-premium" + ), + urlTitleAnchorOpeningTag, + urlActionAnchorOpeningTag, + "", + numberOfLongCenterAlignedTexts + ), + }; + }; + const assessment = new TextAlignmentAssessment( { callbacks: { getResultTexts } } ); + const mockPaperLTR = new Paper( "

This is a paragraph with a bit more than fifty characters.

" + + "

This is another paragraph with a bit more than fifty characters.

" ); + const mockResearcher = new EnglishResearcher( mockPaperLTR ); + mockResearcher.addResearch( "getLongCenterAlignedTexts", getLongCenterAlignedTexts ); + + assessment.getResult( mockPaperLTR, mockResearcher ); + + expect( assessment.getFeedbackStrings() ).toEqual( { + leftToRight: "Alignment: There are 2 long sections of center-aligned text. We recommend making them left-aligned.", + rightToLeft: "Alignment: There are 2 long sections of center-aligned text. We recommend making them right-aligned.", + } ); + } ); +} ); + describe( "tests for the assessment's applicability.", function() { it( "returns false when the paper is empty.", function() { const paperWithNoText = new Paper( "" ); diff --git a/packages/yoastseo/spec/scoring/assessments/readability/WordComplexityAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/WordComplexityAssessmentSpec.js index 3895683c57f..c0448232730 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/WordComplexityAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/WordComplexityAssessmentSpec.js @@ -1,3 +1,4 @@ +import { sprintf, __ } from "@wordpress/i18n"; import wordComplexityConfigEnglish from "../../../../src/languageProcessing/languages/en/config/wordComplexity"; import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher"; import DefaultResearcher from "../../../../src/languageProcessing/languages/_default/Researcher"; @@ -70,7 +71,7 @@ describe( "a test for an assessment that checks complex words in a text", functi const result = assessment.getResult( runningPaper, researcher ); expect( result.getScore() ).toBe( 6 ); - expect( result.getText() ).toBe( "Word complexity: 10.11% of the words in " + + expect( result.getText() ).toBe( "Word complexity: Some words in " + "your text are considered complex. Try to use shorter and more familiar words " + "to improve readability." ); expect( result.hasMarks() ).toBe( true ); @@ -87,7 +88,7 @@ describe( "a test for an assessment that checks complex words in a text", functi const result = assessment.getResult( runningPaper, researcher ); expect( result.getScore() ).toBe( 3 ); - expect( result.getText() ).toBe( "Word complexity: 10.11% of the words in " + + expect( result.getText() ).toBe( "Word complexity: Some words in " + "your text are considered complex. Try to use shorter and more familiar words " + "to improve readability." ); expect( result.hasMarks() ).toBe( true ); @@ -105,7 +106,7 @@ describe( "a test for an assessment that checks complex words in a text", functi const result = assessment.getResult( runningPaper, researcher ); expect( result.getScore() ).toBe( 3 ); - expect( result.getText() ).toBe( "Word complexity: 10% of the words in " + + expect( result.getText() ).toBe( "Word complexity: Some words in " + "your text are considered complex. Try to use shorter and more familiar words " + "to improve readability." ); expect( result.hasMarks() ).toBe( true ); @@ -190,3 +191,81 @@ describe( "tests for the assessment applicability", function() { } ); } ); +describe( "tests for retrieving the feedback strings.", function() { + let researcher; + + beforeEach( () => { + researcher = new EnglishResearcher(); + researcher.addResearch( "wordComplexity", wordComplexity ); + researcher.addHelper( "checkIfWordIsComplex", wordComplexityHelperEnglish ); + researcher.addConfig( "wordComplexity", wordComplexityConfigEnglish ); + researcher.addResearchData( "morphology", morphologyData ); + } ); + + it( "returns the default strings when no custom `getResultTexts` callback is provided.", function() { + const wordComplexityAssessment = new WordComplexityAssessment(); + expect( wordComplexityAssessment.getFeedbackStrings() ).toEqual( { + acceptableAmount: "Word complexity: Some words in your text are considered complex. Try to use shorter and more familiar words to improve readability.", + goodAmount: "Word complexity: You are not using too many complex words, which makes your text easy to read. Good job!", + } ); + } ); + const runningPaper = new Paper( "Also called torties for short, tortoiseshell cats combine two colors other than white, " + + "either closely mixed or in larger patches." + + " The colors are often described as red and black, but the \"red\" patches can instead be orange, yellow, or cream," + + " and the \"black\" can instead be chocolate, gray, tabby, or blue. Tortoiseshell cats with the tabby pattern as one of their colors " + + "are sometimes referred to as a torbie. Cats having torbie coats are sometimes referred to as torbie cats.\n" + + "\"Tortoiseshell\" is typically reserved for particolored cats with relatively small or no white markings. " + + "Those that are predominantly white with tortoiseshell patches are described as tricolor, tortoiseshell-and-white " + + "(in the United Kingdom), or calico (in Canada and the United States).\n" + + "Cats with tortoiseshell pattern and small blotches of white are sometimes referred to as \"tortico\" by their owners, " + + "a portmanteau of \"tortie\" and \"calico\"\n" + + "Torbie cats with a predominantly white undercoat are often referred to as \"caliby\" by their respective owners, " + + "an amalgamation of Calico and Tabby." + + "Torbie cats with a predominantly white undercoat are often referred to as \"caliby\" by their respective owners, " + + "an amalgamation of Calico and Tabby." ); + it( "overrides the default feedback strings when custom `getResultTexts` callback is provided.", function() { + /** + * Returns the result texts for the Word Complexity assessment. + * @param {Object} config The configuration object that contains data needed to generate the result text. + * @param {string} config.urlTitleAnchorOpeningTag The anchor opening tag to the article about this assessment. + * @param {string} config.urlActionAnchorOpeningTag The anchor opening tag to the call to action URL to the help article of this assessment. + * @param {number} config.complexWordsPercentage The percentage of complex words found in the text. + * @returns {{acceptableAmount: string, goodAmount: string}} The object that contains the result texts as a translation string. + */ + const getResultTexts = ( { urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag, complexWordsPercentage } ) => { + return { + acceptableAmount: sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expand to the percentage of the complex words found in the text. + %3$s expand to a link on yoast.com, %4$s expands to the anchor end tag. */ + __( + "%1$sWord complexity%4$s: %2$s of the words in your text are considered complex. %3$sTry to use shorter and more familiar words to improve readability%4$s.", + "wordpress-seo-premium" + ), + urlTitleAnchorOpeningTag, + complexWordsPercentage + "%", + urlActionAnchorOpeningTag, + "" + ), + goodAmount: sprintf( + /* translators: %1$s expands to an article on yoast.com and %4$s expands to the anchor end tag. */ + __( + "%1$sWord complexity%2$s: You are not using too many complex words, which makes your text easy to read. Good job!", + "wordpress-seo-premium" + ), + urlTitleAnchorOpeningTag, + "" + ), + }; + }; + + const wordComplexityAssessment = new WordComplexityAssessment( { callbacks: { getResultTexts } } ); + researcher.setPaper( runningPaper ); + + wordComplexityAssessment.getResult( runningPaper, researcher ); + + expect( wordComplexityAssessment.getFeedbackStrings() ).toEqual( { + acceptableAmount: "Word complexity: 10.11% of the words in your text are considered complex. Try to use shorter and more familiar words to improve readability.", + goodAmount: "Word complexity: You are not using too many complex words, which makes your text easy to read. Good job!", + } ); + } ); +} ); diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/contentAssessorSpec.js b/packages/yoastseo/spec/scoring/assessors/productPages/contentAssessorSpec.js index 4ef503c4a50..9feb561c502 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/contentAssessorSpec.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/contentAssessorSpec.js @@ -16,14 +16,12 @@ const options = { passiveVoiceCTAUrl: "https://yoast.com/10", textPresenceUrlTitle: "https://yoast.com/11", textPresenceCTAUrl: "https://yoast.com/12", - listsUrlTitle: "https://yoast.com/13", - listsCTAUrl: "https://yoast.com/14", }; describe( "A product page content assessor", function() { describe( "Checks the applicable assessments for text containing less than 300 words", function() { - it( "Should have 6 available assessments for a fully supported language. " + - "This doesn't include Word complexity assessment since the registration is done from Shopify side.", function() { + it( "Should have 5 available assessments for a fully supported language. " + + "This doesn't include Word complexity and Lists assessments since the registration is done from Shopify side.", function() { const paper = new Paper( "Lorem ipsum dolor sit amet, voluptua probatus ullamcorper id vis, ceteros consetetur qui ea, " + "nam movet populo aliquam te. His eu debitis fastidii. Pri ea amet dicant. Ut his suas corpora, eu reformidans " + "signiferumque duo. At erant expetenda patrioque quo, rebum atqui nam ad, tempor elaboraret interpretaris pri ad. " + @@ -49,45 +47,11 @@ describe( "A product page content assessor", function() { "textTransitionWords", "passiveVoice", "textPresence", - "listsPresence", ]; expect( actual ).toEqual( expected ); } ); - it( "Should have 7 available assessments for a fully supported language, " + - "including Word complexity assessment after it's research is made available to the researcher.", function() { - const paper = new Paper( "Lorem ipsum dolor sit amet, voluptua probatus ullamcorper id vis, ceteros consetetur qui ea, " + - "nam movet populo aliquam te. His eu debitis fastidii. Pri ea amet dicant. Ut his suas corpora, eu reformidans " + - "signiferumque duo. At erant expetenda patrioque quo, rebum atqui nam ad, tempor elaboraret interpretaris pri ad. " + - "Novum postea sea in. Placerat recteque cu usu. Cu nam sadipscing disputationi, sed labitur elaboraret et. Eu sed " + - "accumsan prodesset. Posse integre et nec, usu assum audiam erroribus eu. Ei viris eirmod interesset usu, " + - "usu homero liberavisse in, solet disputando ea vim. Mei eu inani nonumes consulatu, ea alterum menandri ius, " + - "ne euismod neglegentur sed. Vis te deleniti suscipit, fabellas laboramus pri ei. Te quo aliquip offendit. " + - "Vero paulo regione ei eum, sed at atqui meliore copiosae. Has et vocent vivendum. Mundi graeco latine cum ne, " + - "no cum laoreet alienum. Quo cu vero utinam constituto. Vis omnium vivendum ea. Eum lorem ludus possim ut. Eu has eius " + - "munere explicari, atqui ullamcorper eos no, harum epicuri per ut. Utamur volumus minimum ea vel, duo eu praesent " + - "accommodare. Mutat gloriatur ex cum, rebum salutandi ei his, vis delenit quaestio ne. Iisque qualisque duo ei. " + - "Splendide tincidunt te sit, commune oporteat quo id. Sumo recusabo suscipiantur duo an, no eum malis vulputate " + - "consectetuer. Mel te noster invenire, nec ad vidisse constituto. Eos ut quod.", { locale: "en_US" } ); - const researcher = new EnglishResearcher( paper ); - const contentAssessor = new ContentAssessor( researcher, options ); - - contentAssessor.getPaper = function() { - return paper; - }; - const actual = contentAssessor.getApplicableAssessments().map( result => result.identifier ); - const expected = [ - "textParagraphTooLong", - "textSentenceLength", - "textTransitionWords", - "passiveVoice", - "textPresence", - "listsPresence", - ]; - expect( actual ).toEqual( expected ); - } ); - - it( "Should have 4 available assessments for a basic supported language", function() { + it( "Should have 3 available assessments for a basic supported language", function() { // A text of at least 50 characters. const longEnoughText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis. There is more"; const paper = new Paper( longEnoughText, { locale: "xx_XX" } ); @@ -102,14 +66,13 @@ describe( "A product page content assessor", function() { "textParagraphTooLong", "textSentenceLength", "textPresence", - "listsPresence", ]; expect( actual ).toEqual( expected ); } ); } ); describe( "Checks the applicable assessments for text containing more than 300 words", function() { - it( "Should have 7 available assessments for a fully supported language", function() { + it( "Should have 6 available assessments for a fully supported language", function() { const paper = new Paper( "beautiful cats ".repeat( 200 ), { locale: "en_US" } ); const contentAssessor = new ContentAssessor( new EnglishResearcher( paper ), options ); @@ -124,12 +87,11 @@ describe( "A product page content assessor", function() { "textTransitionWords", "passiveVoice", "textPresence", - "listsPresence", ]; expect( actual ).toEqual( expected ); } ); - it( "Should have 5 available assessments for a basic supported language", function() { + it( "Should have 4 available assessments for a basic supported language", function() { const paper = new Paper( "test ".repeat( 310 ), { locale: "xx_XX" } ); const contentAssessor = new ContentAssessor( new DefaultResearcher( paper ), options ); @@ -143,7 +105,6 @@ describe( "A product page content assessor", function() { "textParagraphTooLong", "textSentenceLength", "textPresence", - "listsPresence", ]; expect( actual ).toEqual( expected ); } ); @@ -164,8 +125,6 @@ describe( "A product page content assessor", function() { passiveVoiceCTAUrl: "https://yoast.com/10", textPresenceUrlTitle: "https://yoast.com/11", textPresenceCTAUrl: "https://yoast.com/12", - listsUrlTitle: "https://yoast.com/13", - listsCTAUrl: "https://yoast.com/14", } ); test( "SubheadingsDistributionTooLong", () => { @@ -228,14 +187,5 @@ describe( "A product page content assessor", function() { expect( assessment._config.urlTitle ).toBe( "" ); expect( assessment._config.urlCallToAction ).toBe( "" ); } ); - - test( "ListsPresence", () => { - const assessment = assessor.getAssessment( "listsPresence" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); } ); } ); diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/contentAssessorSpec.js b/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/contentAssessorSpec.js index 9fed6fd32b5..fcd65a84cbe 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/contentAssessorSpec.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/contentAssessorSpec.js @@ -16,8 +16,6 @@ const options = { passiveVoiceCTAUrl: "https://yoast.com/10", textPresenceUrlTitle: "https://yoast.com/11", textPresenceCTAUrl: "https://yoast.com/12", - listsUrlTitle: "https://yoast.com/13", - listsCTAUrl: "https://yoast.com/14", }; describe( "A cornerstone product page content assessor", function() { @@ -35,7 +33,7 @@ describe( "A cornerstone product page content assessor", function() { "accommodare. Mutat gloriatur ex cum, rebum salutandi ei his, vis delenit quaestio ne. Iisque qualisque duo ei. " + "Splendide tincidunt te sit, commune oporteat quo id. Sumo recusabo suscipiantur duo an, no eum malis vulputate " + "consectetuer. Mel te noster invenire, nec ad vidisse constituto. Eos ut quod." ); - it( "Should have 6 available assessments for a fully supported language. " + + it( "Should have 5 available assessments for a fully supported language. " + "This doesn't include Word complexity assessment since the registration is done from Shopify side.", function() { const contentAssessor = new ContentAssessor( new EnglishResearcher( paper ), options ); contentAssessor.getPaper = function() { @@ -43,43 +41,43 @@ describe( "A cornerstone product page content assessor", function() { }; const actual = contentAssessor.getApplicableAssessments().length; - const expected = 6; + const expected = 5; expect( actual ).toBe( expected ); } ); - it( "Should have 4 available assessments for a basic supported language", function() { + it( "Should have 3 available assessments for a basic supported language", function() { const contentAssessor = new ContentAssessor( new DefaultResearcher( paper ), options ); contentAssessor.getPaper = function() { return paper; }; const actual = contentAssessor.getApplicableAssessments().length; - const expected = 4; + const expected = 3; expect( actual ).toBe( expected ); } ); } ); describe( "Checks the applicable assessments for text that contains more than 300 words", function() { const paper = new Paper( "a tortie cat ".repeat( 150 ) ); - it( "Should have 7 available assessments for a fully supported language", function() { + it( "Should have 6 available assessments for a fully supported language", function() { const contentAssessor = new ContentAssessor( new EnglishResearcher( paper ), options ); contentAssessor.getPaper = function() { return paper; }; const actual = contentAssessor.getApplicableAssessments().length; - const expected = 7; + const expected = 6; expect( actual ).toBe( expected ); } ); - it( "Should have 5 available assessments for a basic supported language", function() { + it( "Should have 4 available assessments for a basic supported language", function() { const contentAssessor = new ContentAssessor( new DefaultResearcher( paper ), options ); contentAssessor.getPaper = function() { return paper; }; const actual = contentAssessor.getApplicableAssessments().length; - const expected = 5; + const expected = 4; expect( actual ).toBe( expected ); } ); } ); @@ -99,8 +97,6 @@ describe( "A cornerstone product page content assessor", function() { passiveVoiceCTAUrl: "https://yoast.com/10", textPresenceUrlTitle: "https://yoast.com/11", textPresenceCTAUrl: "https://yoast.com/12", - listsUrlTitle: "https://yoast.com/13", - listsCTAUrl: "https://yoast.com/14", } ); test( "SubheadingsDistributionTooLong", () => { @@ -164,14 +160,5 @@ describe( "A cornerstone product page content assessor", function() { expect( assessment._config.urlTitle ).toBe( "" ); expect( assessment._config.urlCallToAction ).toBe( "" ); } ); - - test( "ListsPresence", () => { - const assessment = assessor.getAssessment( "listsPresence" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); } ); } ); diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/seoAssessorSpec.js b/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/seoAssessorSpec.js index fdb2b09b74a..014c22ff006 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/seoAssessorSpec.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/cornerstone/seoAssessorSpec.js @@ -1,12 +1,9 @@ import EnglishResearcher from "../../../../../src/languageProcessing/languages/en/Researcher.js"; import Assessor from "../../../../../src/scoring/assessors/productPages/cornerstone/seoAssessor.js"; import Paper from "../../../../../src/values/Paper.js"; -import getResults from "../../../../specHelpers/getAssessorResults"; -import { checkAssessmentAvailability } from "../../../../specHelpers/scoring/seoAssessorTests.js"; const mockPaper = new Paper( "" ); const assessor = new Assessor( new EnglishResearcher( mockPaper ), { - assessVariants: true, introductionKeyphraseUrlTitle: "https://yoast.com/1", introductionKeyphraseCTAUrl: "https://yoast.com/2", keyphraseLengthUrlTitle: "https://yoast.com/3", @@ -37,45 +34,6 @@ const assessor = new Assessor( new EnglishResearcher( mockPaper ), { imageCountCTAUrl: "https://yoast.com/28", imageKeyphraseUrlTitle: "https://yoast.com/29", imageKeyphraseCTAUrl: "https://yoast.com/30", - imageAltTagsUrlTitle: "https://yoast.com/31", - imageAltTagsCTAUrl: "https://yoast.com/32", - keyphraseDistributionUrlTitle: "https://yoast.com/33", - keyphraseDistributionCTAUrl: "https://yoast.com/34", - productIdentifierUrlTitle: "https://yoast.com/35", - productIdentifierCTAUrl: "https://yoast.com/36", - productSKUUrlTitle: "https://yoast.com/37", - productSKUCTAUrl: "https://yoast.com/38", -} ); - -describe( "running assessments in the product page cornerstone SEO assessor", function() { - checkAssessmentAvailability( assessor, true ); - - it( "runs the productSKUAssessments when applicable (canRetrieveVariantSkus is true) that require the SKU to be detectable, " + - "and that shouldn't be applicable if the product has variants and we don't want to assess variants", function() { - const customData = { - canRetrieveGlobalSku: true, - canRetrieveVariantSkus: true, - hasVariants: true, - productType: "variable", - }; - assessor.assess( new Paper( "", { customData } ) ); - const AssessmentResults = assessor.getValidResults(); - const assessments = getResults( AssessmentResults ); - - expect( assessments ).toContain( "productSKU" ); - } ); - - it( "runs the productIdentifierAssessment when it is applicable (it has variants and assessVariants is True)", function() { - const customData = { - hasVariants: true, - productType: "variable", - }; - assessor.assess( new Paper( "", { customData } ) ); - const AssessmentResults = assessor.getValidResults(); - const assessments = getResults( AssessmentResults ); - - expect( assessments ).toContain( "productIdentifier" ); - } ); } ); describe( "has configuration overrides", () => { @@ -239,42 +197,4 @@ describe( "has configuration overrides", () => { expect( assessment._config.urlTitle ).toBe( "" ); expect( assessment._config.urlCallToAction ).toBe( "" ); } ); - - test( "ImageAltTags", () => { - const assessment = assessor.getAssessment( "imageAltTags" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - - test( "KeyphraseDistribution", () => { - const assessment = assessor.getAssessment( "keyphraseDistribution" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - - test( "ProductIdentifierAssessment", () => { - const assessment = assessor.getAssessment( "productIdentifier" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.assessVariants ).toBe( true ); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - - test( "ProductSKUAssessment", () => { - const assessment = assessor.getAssessment( "productSKU" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.assessVariants ).toBe( true ); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); } ); diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/runFullTextTests.js b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/runFullTextTests.js index 1136dfe1ee0..0a70121e742 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/runFullTextTests.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/runFullTextTests.js @@ -134,16 +134,15 @@ testPapers.forEach( function( testPaper ) { urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify55" ), } ); const productIdentifiersAssessment = new ProductIdentifiersAssessment( { - urlTitle: createAnchorOpeningTag( "https://yoa.st/4ly" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/4lz" ), + urlTitle: "https://yoa.st/4ly", + urlCallToAction: "https://yoa.st/4lz", assessVariants: true, } ); const productSKUAssessment = new ProductSKUAssessment( { - urlTitle: createAnchorOpeningTag( "https://yoa.st/4lw" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/4lx" ), + urlTitle: "https://yoa.st/4lw", + urlCallToAction: "https://yoa.st/4lx", assessVariants: true, productType: "simple", - addSKULocation: true, } ); const imageKeyphraseAssessment = new ImageKeyphraseAssessment( { urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify22" ), @@ -158,8 +157,8 @@ testPapers.forEach( function( testPaper ) { urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify21" ), }, true ); const imageAltTagsAsessment = new ImageAltTags( { - urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify40" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify41" ), + urlTitle: "https://yoa.st/shopify40", + urlCallToAction: "https://yoa.st/shopify41", } ); const keyphraseDistributionAssessment = new KeyphraseDistribution( { urlTitle: "https://yoa.st/shopify30", @@ -197,8 +196,8 @@ testPapers.forEach( function( testPaper ) { urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify57" ), } ); const listPresenceAssessment = new ListAssessment( { - urlTitle: createAnchorOpeningTag( "https://yoa.st/shopify38" ), - urlCallToAction: createAnchorOpeningTag( "https://yoa.st/shopify39" ), + urlTitle: "https://yoa.st/shopify38", + urlCallToAction: "https://yoa.st/shopify39", } ); const wordComplexityAssessment = new WordComplexityAssessment( { urlTitle: "https://yoa.st/shopify77", diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper1.js b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper1.js index 247eabefeaf..359e3d98e73 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper1.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper1.js @@ -116,7 +116,7 @@ const expectedResults = { imageAltTags: { isApplicable: true, score: 3, - resultText: "Image alt tags: 1 image out of 4 doesn't have alt attributes." + + resultText: "Image alt tags: One image doesn't have alt attributes." + " Add alt attributes to your images!", }, keyphraseDistribution: { diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/seoAssessorSpec.js b/packages/yoastseo/spec/scoring/assessors/productPages/seoAssessorSpec.js index b85d8e9d4f6..edcc82529fe 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/seoAssessorSpec.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/seoAssessorSpec.js @@ -1,12 +1,9 @@ import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher.js"; import Assessor from "../../../../src/scoring/assessors/productPages/seoAssessor.js"; import Paper from "../../../../src/values/Paper.js"; -import getResults from "../../../specHelpers/getAssessorResults.js"; -import { checkAssessmentAvailability } from "../../../specHelpers/scoring/seoAssessorTests.js"; const mockPaper = new Paper( "" ); const assessor = new Assessor( new EnglishResearcher( mockPaper ), { - assessVariants: true, introductionKeyphraseUrlTitle: "https://yoast.com/1", introductionKeyphraseCTAUrl: "https://yoast.com/2", keyphraseLengthUrlTitle: "https://yoast.com/3", @@ -37,45 +34,6 @@ const assessor = new Assessor( new EnglishResearcher( mockPaper ), { imageCountCTAUrl: "https://yoast.com/28", imageKeyphraseUrlTitle: "https://yoast.com/29", imageKeyphraseCTAUrl: "https://yoast.com/30", - imageAltTagsUrlTitle: "https://yoast.com/31", - imageAltTagsCTAUrl: "https://yoast.com/32", - keyphraseDistributionUrlTitle: "https://yoast.com/33", - keyphraseDistributionCTAUrl: "https://yoast.com/34", - productIdentifierUrlTitle: "https://yoast.com/35", - productIdentifierCTAUrl: "https://yoast.com/36", - productSKUUrlTitle: "https://yoast.com/37", - productSKUCTAUrl: "https://yoast.com/38", -} ); - -describe( "running assessments in the product page SEO assessor", function() { - checkAssessmentAvailability( assessor, true ); - - it( "runs the productSKUAssessments when applicable (canRetrieveVariantSkus is true) that require the SKU to be detectable, " + - "and that shouldn't be applicable if the product has variants and we don't want to assess variants", function() { - const customData = { - canRetrieveGlobalSku: true, - canRetrieveVariantSkus: true, - hasVariants: true, - productType: "variable", - }; - assessor.assess( new Paper( "", { customData } ) ); - const AssessmentResults = assessor.getValidResults(); - const assessments = getResults( AssessmentResults ); - - expect( assessments ).toContain( "productSKU" ); - } ); - - it( "runs the productIdentifierAssessment when it is applicable (it has variants and assessVariants is True)", function() { - const customData = { - hasVariants: true, - productType: "variable", - }; - assessor.assess( new Paper( "", { customData } ) ); - const AssessmentResults = assessor.getValidResults(); - const assessments = getResults( AssessmentResults ); - - expect( assessments ).toContain( "productIdentifier" ); - } ); } ); describe( "has configuration overrides", () => { @@ -226,40 +184,4 @@ describe( "has configuration overrides", () => { expect( assessment._config.urlTitle ).toBe( "" ); expect( assessment._config.urlCallToAction ).toBe( "" ); } ); - - test( "ImageAltTags", () => { - const assessment = assessor.getAssessment( "imageAltTags" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - - test( "KeyphraseDistribution", () => { - const assessment = assessor.getAssessment( "keyphraseDistribution" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - test( "ProductIdentifierAssessment", () => { - const assessment = assessor.getAssessment( "productIdentifier" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.assessVariants ).toBe( true ); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); - test( "ProductSKUAssessment", () => { - const assessment = assessor.getAssessment( "productSKU" ); - - expect( assessment ).toBeDefined(); - expect( assessment._config ).toBeDefined(); - expect( assessment._config.assessVariants ).toBe( true ); - expect( assessment._config.urlTitle ).toBe( "" ); - expect( assessment._config.urlCallToAction ).toBe( "" ); - } ); } ); diff --git a/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js b/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js index 1df057a3300..453af0adee4 100644 --- a/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js +++ b/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js @@ -1,7 +1,7 @@ import getResults from "../getAssessorResults"; import Paper from "../../../src/values/Paper"; import KeyphraseDistributionAssessment from "../../../src/scoring/assessments/seo/KeyphraseDistributionAssessment"; -import keyPhraseDistribution from "../../../src/languageProcessing/researches/keyphraseDistribution"; +import keyphraseDistribution from "../../../src/languageProcessing/researches/keyphraseDistribution"; /* eslint-disable complexity */ /* eslint-disable max-statements */ @@ -29,7 +29,7 @@ export function checkAssessmentAvailability( assessor, isProductAssessor = false if ( isProductAssessor && ! isStoreBlog ) { // Add the Keyphrase distribution assessment to the assessor, which is available in these assessors in Shopify. - assessor._researcher.addResearch( "keyphraseDistribution", keyPhraseDistribution ); + assessor._researcher.addResearch( "keyphraseDistribution", keyphraseDistribution ); assessor.addAssessment( "keyphraseDistribution", new KeyphraseDistributionAssessment( { urlTitle: isProduct ? "https://yoast.com/33" : "https://yoa.st/shopify30", urlCallToAction: isProduct ? "https://yoast.com/34" : "https://yoa.st/shopify31", diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js index 68e76ab6e3d..1f3418adca2 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductIdentifiersAssessment.js @@ -72,7 +72,7 @@ export default class ProductIdentifiersAssessment extends Assessment { } /** - * Checks whether the assessment is applicable. It is applicable unless the product has variants and we don't want to + * Checks whether the assessment is applicable. It is applicable unless the product has variants, and we don't want to * assess variants (this is the case for Shopify since we cannot at the moment easily access variant data in Shopify). * * @param {Paper} paper The paper to check. From 00338a0374b8569c768cd610b6212bcef458d95f Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 5 Sep 2024 11:23:00 +0200 Subject: [PATCH 21/24] Adapt unit test --- .../yoastseo/spec/specHelpers/scoring/seoAssessorTests.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js b/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js index 453af0adee4..cf7f579feb3 100644 --- a/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js +++ b/packages/yoastseo/spec/specHelpers/scoring/seoAssessorTests.js @@ -397,8 +397,12 @@ export function checkUrls( assessor, isProductAssessor = false ) { const assessment = assessor.getAssessment( "keyphraseDistribution" ); const urlTitle = isProductAssessor ? "https://yoa.st/shopify30" : "https://yoa.st/33q"; const urlCallToAction = isProductAssessor ? "https://yoa.st/shopify31" : "https://yoa.st/33u"; - - checkAssessmentUrls( assessment, urlTitle, urlCallToAction ); + // Only test this for product assessors, as the product specific/premium assessments have different URLs: they are not transformed into anchor opening tags. + if ( assessment ) { + expect( assessment._config ).toBeDefined(); + expect( assessment._config.urlTitle ).toBe( urlTitle ); + expect( assessment._config.urlCallToAction ).toBe( urlCallToAction ); + } } ); test( "OutboundLinks", () => { From 939282e7a1cca180967f7f7226f68583342be649 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 5 Sep 2024 12:31:40 +0200 Subject: [PATCH 22/24] Add unit tests --- .../readability/ListAssessmentSpec.js | 17 +++++++++++++++ .../KeyphraseDistributionAssessmentSpec.js | 21 +++++++++++++++++++ .../seo/TextTitleAssessmentSpec.js | 13 ++++++++++++ 3 files changed, 51 insertions(+) diff --git a/packages/yoastseo/spec/scoring/assessments/readability/ListAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/ListAssessmentSpec.js index 90d9c42c5c4..fa0817ec6ec 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/ListAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/ListAssessmentSpec.js @@ -74,3 +74,20 @@ describe( "tests for the assessment applicability.", function() { expect( listAssessment.isApplicable( paper ) ).toBe( false ); } ); } ); + +describe( "a test for retrieving the feedback texts", () => { + it( "should return the custom feedback texts when `callbacks.getResultTexts` is provided", () => { + const assessment = new ListAssessment( { + callbacks: { + getResultTexts: () => ( { + good: "This text has a list.", + bad: "This text doesn't have a list.", + } ), + }, + } ); + expect( assessment.getFeedbackStrings() ).toEqual( { + good: "This text has a list.", + bad: "This text doesn't have a list.", + } ); + } ); +} ); diff --git a/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseDistributionAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseDistributionAssessmentSpec.js index 7f1b124f8c9..16ccb7aa2da 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseDistributionAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseDistributionAssessmentSpec.js @@ -249,3 +249,24 @@ describe( "A test for marking keywords in the text", function() { expect( keyphraseDistributionAssessment.getMarks() ).toEqual( [] ); } ); } ); + +describe( "a test for retrieving the feedback texts", () => { + it( "should return the custom feedback texts when `callbacks.getResultTexts` is provided", () => { + const assessment = new KeyphraseDistributionAssessment( { + callbacks: { + getResultTexts: () => ( { + good: "The text has a good keyphrase distribution.", + okay: "Some parts of your text do not contain the keyphrase or its synonyms. Distribute them more evenly.", + bad: "Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. Distribute them more evenly.", + consideration: "Include your keyphrase or its synonyms in the text so that we can check keyphrase distribution.", + } ), + }, + } ); + expect( assessment.getFeedbackStrings() ).toEqual( { + good: "The text has a good keyphrase distribution.", + okay: "Some parts of your text do not contain the keyphrase or its synonyms. Distribute them more evenly.", + bad: "Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. Distribute them more evenly.", + consideration: "Include your keyphrase or its synonyms in the text so that we can check keyphrase distribution.", + } ); + } ); +} ); diff --git a/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js index d06bec6900c..c232f58867e 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js @@ -43,3 +43,16 @@ describe( "a test to check whether a text has a title or not", () => { } ); } ); +describe( "a test for retrieving the feedback texts", () => { + it( "should return the custom feedback texts when `callbacks.getResultTexts` is provided", () => { + const assessment = new TextTitleAssessment( { + callbacks: { + getResultTexts: () => ( { + good: "This text has a title.", + bad: "This text doesn't have a title.", + } ), + }, + } ); + expect( assessment.getFeedbackStrings() ).toEqual( { bad: "This text doesn't have a title.", good: "This text has a title." } ); + } ); +} ); From 9ad9fb5f2fb5165cd05a18c9059ccfd30e4e67de Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 5 Sep 2024 16:06:17 +0200 Subject: [PATCH 23/24] Fix typo in analysis doc --- packages/yoastseo/src/scoring/assessments/SCORING SEO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/yoastseo/src/scoring/assessments/SCORING SEO.md b/packages/yoastseo/src/scoring/assessments/SCORING SEO.md index b37967b69e7..3777bfb61f0 100644 --- a/packages/yoastseo/src/scoring/assessments/SCORING SEO.md +++ b/packages/yoastseo/src/scoring/assessments/SCORING SEO.md @@ -253,7 +253,7 @@ With the example keyphrase `cat and dog` the following criteria would apply to c |------------ |------------------ |--------------------- |--------------- | | Grey | 0 | Keyphrase was not set or not used in the text | **Keyphrase distribution**: **Include your keyphrase or its synonyms in the text so that we can check keyword distribution.** | | Red | 1 | The resulting score is >0.6 | **Keyphrase distribution**: Very uneven. Large parts of your text do not contain the keyphrase or its synonyms. **Distibute them more evenly.** | -| Orange | 6 | The resulting score is between 0.4 and 0.6 | between 0.4 and 0.6 **Keyphrase distribution**: Uneven. Some parts of your text do not contain your keyphrase or its synonyms. **Distribute them more evenly.** | +| Orange | 6 | The resulting score is between 0.4 and 0.6 | **Keyphrase distribution**: Uneven. Some parts of your text do not contain your keyphrase or its synonyms. **Distribute them more evenly.** | | Green | 9 | The resulting score is <0.4 | **Keyphrase distribution**: Good job! | ## Other SEO assessments scoring criteria From 3a161f47628d4bb6e6e6d0c98d738f5d1db7c0a0 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Thu, 12 Sep 2024 12:21:37 +0200 Subject: [PATCH 24/24] Adapt the default feedback string for SKU assessment --- .../scoring/assessments/seo/ProductSKUAssessmentSpec.js | 8 +++----- .../fullTextTests/testTexts/en/englishPaper3.js | 3 +-- .../src/scoring/assessments/seo/ProductSKUAssessment.js | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js index 57e40f04dcd..b2ce16f62a1 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/ProductSKUAssessmentSpec.js @@ -98,8 +98,7 @@ describe( "a test for SKU assessment for WooCommerce", function() { expect( assessmentResult.getScore() ).toEqual( 6 ); expect( assessmentResult.getText() ).toEqual( "SKU:" + - " Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product " + - "data box. Include it if you can, as it will help search " + + " Not all your product variants have a SKU. Include it if you can, as it will help search " + "engines to better understand your content." ); } ); @@ -116,8 +115,7 @@ describe( "a test for SKU assessment for WooCommerce", function() { expect( assessmentResult.getScore() ).toEqual( 6 ); expect( assessmentResult.getText() ).toEqual( "SKU:" + - " Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product " + - "data box. Include it if you can, as it will help search " + + " Not all your product variants have a SKU. Include it if you can, as it will help search " + "engines to better understand your content." ); } ); @@ -213,7 +211,7 @@ describe( "a test for SKU assessment for Shopify", () => { withVariants: sprintf( /* translators: %1$s and %2$s expand to links on yoast.com, %3$s expands to the anchor end tag. */ __( - "%1$sSKU%3$s: Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product data box. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + "%1$sSKU%3$s: Not all your product variants have a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", "yoast-woo-seo" ), urlTitleAnchorOpeningTag, diff --git a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper3.js b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper3.js index 6b6b28c962a..a18c426ffcd 100644 --- a/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper3.js +++ b/packages/yoastseo/spec/scoring/assessors/productPages/fullTextTests/testTexts/en/englishPaper3.js @@ -107,8 +107,7 @@ const expectedResults = { productSKU: { isApplicable: true, score: 6, - resultText: "SKU: Not all your product variants have a SKU. You can add a SKU via " + - "the \"Variations\" tab in the Product data box. Include " + + resultText: "SKU: Not all your product variants have a SKU. Include " + "it if you can, as it will help search engines to better understand your content.", }, imageKeyphrase: { diff --git a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js index b55b72fd09c..ee6c951cda8 100644 --- a/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/seo/ProductSKUAssessment.js @@ -170,7 +170,7 @@ export default class ProductSKUAssessment extends Assessment { }, okay: { withoutVariants: "%1$sSKU%3$s: Your product is missing a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", - withVariants: "%1$sSKU%3$s: Not all your product variants have a SKU. You can add a SKU via the \"Variations\" tab in the Product data box. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", + withVariants: "%1$sSKU%3$s: Not all your product variants have a SKU. %2$sInclude it if you can, as it will help search engines to better understand your content.%3$s", }, }; defaultResultTexts.good = mapValues(