yoastseo
Version:
Yoast client-side content analysis
184 lines (175 loc) • 8.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _lodash = require("lodash");
var _assessment = _interopRequireDefault(require("../assessment"));
var _AssessmentResult = _interopRequireDefault(require("../../../values/AssessmentResult"));
var _helpers = require("../../../helpers");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Represents the assessment that checks whether a product has identifier(s).
*/
class ProductIdentifiersAssessment extends _assessment.default {
/**
* 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] The callbacks to use for the assessment.
* @param {function} [config.callbacks.getResultTexts] The function that returns the result texts.
*
* @returns {void}
*/
constructor(config = {}) {
super();
const defaultConfig = {
scores: {
good: 9,
ok: 6
},
urlTitle: "https://yoa.st/4ly",
urlCallToAction: "https://yoa.st/4lz",
assessVariants: false,
shouldShowEditButton: false,
editFieldAriaLabel: "Edit your product identifiers",
callbacks: {}
};
this.identifier = "productIdentifier";
this._config = (0, _lodash.merge)(defaultConfig, config);
}
/**
* Executes the assessment and returns a result based on the research.
*
* @param {Paper} paper The paper to use for the assessment.
*
* @returns {AssessmentResult} An assessment result with the score and formatted text.
*/
getResult(paper) {
const productIdentifierData = paper.getCustomData();
const result = this.scoreProductIdentifier(productIdentifierData, this._config);
const assessmentResult = new _AssessmentResult.default();
if (result) {
assessmentResult.setScore(result.score);
assessmentResult.setText(result.text);
}
if (assessmentResult.getScore() < 9 && this._config.shouldShowEditButton) {
assessmentResult.setHasJumps(true);
assessmentResult.setEditFieldName("productIdentifier");
// Provide `this._config.editFieldAriaLabel` when initialize this assessment with the value "Edit your product identifiers". We recommend to provide the string as a translation string.
assessmentResult.setEditFieldAriaLabel(this._config.editFieldAriaLabel);
}
return assessmentResult;
}
/**
* 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.
*
* @returns {Boolean} Whether the assessment is applicable.
*/
isApplicable(paper) {
const customData = paper.getCustomData();
/*
* If the global identifier cannot be retrieved, the assessment shouldn't be applicable if the product is a simple
* or external product, or doesn't have variants. Even though in reality a simple or external product doesn't have variants,
* this double check is added because the hasVariants variable doesn't always update correctly when changing product type.
*/
if (customData.canRetrieveGlobalIdentifier === false && (["simple", "external", "grouped"].includes(customData.productType) || customData.hasVariants === false)) {
return false;
}
// If variant identifiers cannot be retrieved for a variable product with variants, the assessment shouldn't be applicable.
if (customData.canRetrieveVariantIdentifiers === false && customData.hasVariants === true && customData.productType === "variable") {
return false;
}
// Assessment is not applicable if we don't want to assess variants and the product has variants.
return !(this._config.assessVariants === false && customData.hasVariants);
}
/**
* Returns a score based on whether the product (variants) have an identifier.
*
* @param {Object} productIdentifierData Whether product has variants, global identifier, and variant identifiers.
* @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.
*/
scoreProductIdentifier(productIdentifierData, config) {
const {
good,
okay
} = this.getFeedbackStrings();
// Apply the following scoring conditions to products without variants.
if (["simple", "grouped", "external"].includes(productIdentifierData.productType) || productIdentifierData.productType === "variable" && !productIdentifierData.hasVariants) {
if (!productIdentifierData.hasGlobalIdentifier) {
return {
score: config.scores.ok,
text: okay.withoutVariants
};
}
return {
score: config.scores.good,
text: good.withoutVariants
};
} else if (productIdentifierData.productType === "variable" && productIdentifierData.hasVariants) {
if (!productIdentifierData.doAllVariantsHaveIdentifier) {
// If we want to assess variants, and if product has variants but not all variants have an identifier, return orange bullet.
// If all variants have an identifier, return green bullet.
return {
score: config.scores.ok,
text: okay.withVariants
};
}
return {
score: config.scores.good,
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() {
// `urlTitleAnchorOpeningTag` represents the anchor opening tag with the URL to the article about this assessment.
const urlTitleAnchorOpeningTag = (0, _helpers.createAnchorOpeningTag)(this._config.urlTitle);
// `urlActionAnchorOpeningTag` represents the anchor opening tag with the URL for the call to action.
const urlActionAnchorOpeningTag = (0, _helpers.createAnchorOpeningTag)(this._config.urlCallToAction);
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$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"
}
};
defaultResultTexts.good = (0, _lodash.mapValues)(defaultResultTexts.good, resultText => this.formatResultText(resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag));
defaultResultTexts.okay = (0, _lodash.mapValues)(defaultResultTexts.okay, resultText => this.formatResultText(resultText, urlTitleAnchorOpeningTag, urlActionAnchorOpeningTag));
return defaultResultTexts;
}
return this._config.callbacks.getResultTexts({
urlTitleAnchorOpeningTag,
urlActionAnchorOpeningTag
});
}
}
exports.default = ProductIdentifiersAssessment;
//# sourceMappingURL=ProductIdentifiersAssessment.js.map