yoastseo-dep
Version:
Yoast clientside page analysis
128 lines (104 loc) • 4.62 kB
JavaScript
/** @module analyses/findKeyphraseInSEOTitle */
import wordMatch from "../helpers/match/matchTextWithWord.js";
import { findTopicFormsInString } from "../helpers/match/findKeywordFormsInString.js";
import { escapeRegExp, filter, includes, isEmpty } from "lodash-es";
import processExactMatchRequest from "../helpers/match/processExactMatchRequest";
import getWords from "../helpers/word/getWords";
let functionWords = [];
/**
* Strips all function words from the start of the given string.
*
* @param {string} str The string from which to strip the function words.
*
* @returns {boolean} Whether the string consists of function words only.
*/
const stripFunctionWordsFromStart = function( str ) {
str = str.toLocaleLowerCase();
let titleWords = getWords( str.toLocaleLowerCase() );
// Strip all function words from the start of the string.
titleWords = filter( titleWords, function( word ) {
return ( ! includes( functionWords, word.trim().toLocaleLowerCase() ) );
} );
return isEmpty( titleWords );
};
/**
* Checks the position of the keyphrase in the SEO title.
*
* @param {string} title The SEO title of the paper.
* @param {number} position The position of the keyphrase in the SEO title.
*
* @returns {number} Potentially adjusted position of the keyphrase in the SEO title.
*/
const adjustPosition = function( title, position ) {
// Don't do anything if position if already 0.
if ( position === 0 ) {
return position;
}
// Don't do anything if no function words exist for this language.
if ( functionWords.length === 0 ) {
return position;
}
// Strip all function words from the beginning of the SEO title.
const titleBeforeKeyword = title.substr( 0, position );
if ( stripFunctionWordsFromStart( titleBeforeKeyword ) ) {
/*
* Return position 0 if there are no words left in the SEO title before the keyword after filtering
* the function words (such that "keyword" in "the keyword" is still counted as position 0).
*/
return 0;
}
return position;
};
/**
* Counts the occurrences of the keyword in the SEO title. Returns the result that contains information on
* (1) whether the exact match of the keyphrase was used in the SEO title,
* (2) whether all (content) words from the keyphrase were found in the SEO title,
* (3) at which position the exact match was found in the SEO title.
*
* @param {Object} paper The paper containing SEO title and keyword.
* @param {Researcher} researcher The researcher to use for analysis.
*
* @returns {Object} An object containing the information on whether the keyphrase was matched in the SEO title and how.
*/
const findKeyphraseInSEOTitle = function( paper, researcher ) {
functionWords = researcher.getConfig( "functionWords" );
let keyword = escapeRegExp( paper.getKeyword() );
const title = paper.getTitle();
const locale = paper.getLocale();
const result = { exactMatchFound: false, allWordsFound: false, position: -1, exactMatchKeyphrase: false };
// Check if the keyphrase is enclosed in double quotation marks to ensure that only exact matches are processed.
const exactMatchRequest = processExactMatchRequest( keyword );
if ( exactMatchRequest.exactMatchRequested ) {
keyword = exactMatchRequest.keyphrase;
result.exactMatchKeyphrase = true;
}
// Check if the exact match of the keyphrase is found in the SEO title.
const keywordMatched = wordMatch( title, keyword, locale, false );
if ( keywordMatched.count > 0 ) {
result.exactMatchFound = true;
result.allWordsFound = true;
result.position = adjustPosition( title, keywordMatched.position );
return result;
}
// If an exact match was not found, check the pre-sanitized version of the keyphrase for matching.
// This makes matching of keyphrases containing punctuation (e.g. ".rar") possible.
if ( ! keywordMatched ) {
const keywordMatchedBeforeSanitizing = keyword;
if ( keywordMatchedBeforeSanitizing.count > 0 ) {
result.exactMatchFound = true;
result.allWordsFound = true;
result.position = adjustPosition( title, keywordMatchedBeforeSanitizing.position );
}
return result;
}
// Check 2: Are all content words from the keyphrase in the SEO title?
const topicForms = researcher.getResearch( "morphology" );
// Use only keyphrase (not the synonyms) to match topic words in the SEO title.
const useSynonyms = false;
const separateWordsMatched = findTopicFormsInString( topicForms, title, useSynonyms, locale, false );
if ( separateWordsMatched.percentWordMatches === 100 ) {
result.allWordsFound = true;
}
return result;
};
export default findKeyphraseInSEOTitle;