Skip to content

Commit

Permalink
Merge branch 'feature/wincher-modal-improvements' of https://github.c…
Browse files Browse the repository at this point in the history
…om/wincher-ab/wordpress-seo into wincher-modal-improvements
  • Loading branch information
pls78 committed Oct 13, 2023
2 parents f164f45 + 6a4a84c commit ab4b3f1
Show file tree
Hide file tree
Showing 24 changed files with 281 additions and 201 deletions.
26 changes: 13 additions & 13 deletions inc/options/class-wpseo-option.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

/**
* This abstract class and it's concrete classes implement defaults and value validation for
* This abstract class and its concrete classes implement defaults and value validation for
* all WPSEO options and subkeys within options.
*
* Some guidelines:
Expand All @@ -22,9 +22,9 @@
*
* [Updating/Adding options]
* - For multisite site_options, please use the WPSEO_Options::update_site_option() method.
* - For normal options, use the normal add/update_option() functions. As long a the classes here
* - For normal options, use the normal add/update_option() functions. As long as the classes here
* are instantiated, validation for all options and their subkeys will be automatic.
* - On (succesfull) update of a couple of options, certain related actions will be run automatically.
* - On (successful) update of a couple of options, certain related actions will be run automatically.
* Some examples:
* - on change of wpseo[yoast_tracking], the cron schedule will be adjusted accordingly
* - on change of wpseo and wpseo_title, some caches will be cleared
Expand All @@ -41,7 +41,7 @@
* translate_defaults() method.
* - When you remove an array key from an option: if it's important that the option is really removed,
* add the WPSEO_Option::clean_up( $option_name ) method to the upgrade run.
* This will re-save the option and automatically remove the array key no longer in existance.
* This will re-save the option and automatically remove the array key no longer in existence.
* - When you rename a sub-option: add it to the clean_option() routine and run that in the upgrade run.
* - When you change the default for an option sub-key, make sure you verify that the validation routine will
* still work the way it should.
Expand Down Expand Up @@ -74,8 +74,8 @@ abstract class WPSEO_Option {
* Option group name for use in settings forms.
*
* Will be set automagically if not set in concrete class (i.e.
* if it confirm to the normal pattern 'yoast' . $option_name . 'options',
* only set in conrete class if it doesn't).
* if it conforms to the normal pattern 'yoast' . $option_name . 'options',
* only set in concrete class if it doesn't).
*
* @var string
*/
Expand Down Expand Up @@ -107,7 +107,7 @@ abstract class WPSEO_Option {
protected $defaults;

/**
* Array of variable option name patterns for the option - if any -.
* Array of variable option name patterns for the option - if any.
*
* Set this when the option contains array keys which vary based on post_type
* or taxonomy.
Expand Down Expand Up @@ -230,7 +230,7 @@ protected function __construct() {
* ```
* ---------------
*
* Concrete classes *may* contain a enrich_defaults method to add additional defaults once
* Concrete classes *may* contain an enrich_defaults method to add additional defaults once
* all post_types and taxonomies have been registered.
*
* ```
Expand Down Expand Up @@ -497,7 +497,7 @@ public function get_option( $options = null ) {
return $filtered;
}

/* *********** METHODS influencing add_uption(), update_option() and saving from admin pages. *********** */
/* *********** METHODS influencing add_option(), update_option() and saving from admin pages. *********** */

/**
* Register (whitelist) the option for the configuration pages.
Expand All @@ -523,7 +523,7 @@ public function register_setting() {
}

/**
* Validate the option
* Validate the option.
*
* @param mixed $option_value The unvalidated new value for the option.
*
Expand Down Expand Up @@ -645,7 +645,7 @@ public function maybe_add_option() {
*
* @param mixed $value The new value for the option.
*
* @return bool Whether the update was succesfull.
* @return bool Whether the update was successful.
*/
public function update_site_option( $value ) {
if ( $this->multisite_only === true && is_multisite() ) {
Expand All @@ -667,7 +667,7 @@ public function update_site_option( $value ) {
* @uses WPSEO_Option::import()
*
* @param string|null $current_version Optional. Version from which to upgrade, if not set,
* version specific upgrades will be disregarded.
* version-specific upgrades will be disregarded.
*
* @return void
*/
Expand All @@ -692,7 +692,7 @@ public function clean( $current_version = null ) {
*
* @param array $option_value Option value to be imported.
* @param string|null $current_version Optional. Version from which to upgrade, if not set,
* version specific upgrades will be disregarded.
* version-specific upgrades will be disregarded.
* @param array|null $all_old_option_values Optional. Only used when importing old options to
* have access to the real old values, in contrast to
* the saved ones.
Expand Down
2 changes: 1 addition & 1 deletion inc/sitemaps/class-taxonomy-sitemap-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public function is_valid_taxonomy( $taxonomy_name ) {
return false;
}

if ( in_array( $taxonomy_name, [ 'link_category', 'nav_menu' ], true ) ) {
if ( in_array( $taxonomy_name, [ 'link_category', 'nav_menu', 'wp_pattern_category' ], true ) ) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"typescript": "^4.2.4"
},
"yoast": {
"pluginVersion": "21.4-RC4"
"pluginVersion": "21.4-RC6"
},
"version": "0.0.0"
}
1 change: 1 addition & 0 deletions packages/js/src/components/WincherSEOPerformance.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ const TableContent = ( props ) => {
return [];
}
return Object.values( trackedKeyphrases )
.filter( keyphrase => !! keyphrase?.position?.history )
.map( keyphrase => ( {
label: keyphrase.keyword,
data: keyphrase.position.history,
Expand Down
2 changes: 1 addition & 1 deletion packages/js/src/decorator/helpers/getAnnotationsHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export const getAnnotationsForFAQ = ( attributeWithAnnotationSupport, block, mar
*/
export const getAnnotationsForHowTo = ( attributeWithAnnotationSupport, block, marks ) => {
const annotatableTextsFromBlock = block.attributes[ attributeWithAnnotationSupport.key ];
if ( annotatableTextsFromBlock.length === 0 ) {
if ( annotatableTextsFromBlock && annotatableTextsFromBlock.length === 0 ) {
return [];
}
const annotations = [];
Expand Down
39 changes: 27 additions & 12 deletions packages/js/src/decorator/helpers/positionBasedAnnotationHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { helpers } from "yoastseo";
/**
* Regex to detect HTML tags.
* Please note that this regex will also detect non-HTML tags that are also wrapped in `<>`.
* For example, in the following sentence, <strong class="">cats <dogs> rabbit </strong>,
* we will match <strong class="">, <dogs> and </strong>. This is an edge case though.
* For example, in the following sentence, `<strong class="">cats <dogs> rabbit </strong>`,
* we will match `<strong class="">`, `<dogs>` and `</strong>`. This is an edge case though.
* @type {RegExp}
*/
const htmlTagsRegex = /(<([a-z]|\/)[^<>]+>)/ig;
Expand Down Expand Up @@ -53,6 +53,27 @@ const adjustFirstSectionOffsets = ( blockStartOffset, blockEndOffset, blockName
return { blockStartOffset, blockEndOffset };
};

/**
* Retrieves the length for HTML tags, adjusts the length for `<br>` tags.
* @param {[Object]} htmlTags Array of HTML tags.
* @returns {number} The length of the given HTML tags.
*/
const getTagsLength = ( htmlTags ) => {
let tagsLength = 0;
forEachRight( htmlTags, ( htmlTag ) => {
const [ tag ] = htmlTag;
let tagLength = tag.length;
// Here, we need to account for treating <br> tags as sentence delimiters, and subtract 1 from the tagLength.
if ( /^<\/?br/.test( tag ) ) {
tagLength -= 1;
}

tagsLength += tagLength;
} );

return tagsLength;
};

/**
* Adjusts the block start and end offsets of a given Mark when the block HTML contains HTML tags.
*
Expand Down Expand Up @@ -80,17 +101,11 @@ const adjustOffsetsForHtmlTags = ( slicedBlockHtmlToStartOffset, slicedBlockHtml
* - Text: This is a giant panda.
* - Range of "panda": 16 -21
*/
let foundHtmlTags = [ ...slicedBlockHtmlToStartOffset.matchAll( htmlTagsRegex ) ];
forEachRight( foundHtmlTags, ( foundHtmlTag ) => {
const [ tag ] = foundHtmlTag;
blockStartOffset -= tag.length;
} );
const foundHtmlTagsToStartOffset = [ ...slicedBlockHtmlToStartOffset.matchAll( htmlTagsRegex ) ];
blockStartOffset -= getTagsLength( foundHtmlTagsToStartOffset );

foundHtmlTags = [ ...slicedBlockHtmlToEndOffset.matchAll( htmlTagsRegex ) ];
forEachRight( foundHtmlTags, ( foundHtmlTag ) => {
const [ tag ] = foundHtmlTag;
blockEndOffset -= tag.length;
} );
const foundHtmlTagsToEndOffset = [ ...slicedBlockHtmlToEndOffset.matchAll( htmlTagsRegex ) ];
blockEndOffset -= getTagsLength( foundHtmlTagsToEndOffset );

return { blockStartOffset, blockEndOffset };
};
Expand Down
12 changes: 4 additions & 8 deletions packages/js/src/settings/routes/breadcrumbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,8 @@ const Breadcrumbs = () => {
as={ SelectField }
name={ `wpseo_titles.post_types-${ postTypeName }-maintax` }
id={ `input-wpseo_titles-post_types-${ postTypeName }-maintax` }
label={ <>
{ postType.label }
<Code className="yst-ml-2">{ postTypeName }</Code>
</> }
label={ postType.label }
labelSuffix={ <Code className="yst-ml-2">{ postTypeName }</Code> }
options={ postType.options }
className="yst-max-w-sm"
/> ) }
Expand All @@ -131,12 +129,10 @@ const Breadcrumbs = () => {
as={ SelectField }
name={ `wpseo_titles.taxonomy-${ taxonomy.name }-ptparent` }
id={ `input-wpseo_titles-taxonomy-${ taxonomy.name }-ptparent` }
label={ <>
{ taxonomy.label }
<Code className="yst-ml-2">{ taxonomy.name }</Code>
</> }
label={ taxonomy.label }
options={ taxonomy.options }
className="yst-max-w-sm"
labelSuffix={ <Code className="yst-ml-2">{ taxonomy.name }</Code> }
/>
) ) }
</FieldsetLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ const testCases = [
attributeId: "",
clientId: "",
isFirstSection: false } } ),
],
],
skip: false,
},
{
Expand Down Expand Up @@ -953,6 +953,41 @@ const testCasesWithSpecialCharacters = [
],
skip: false,
},
{
description: "can match keyphrases in texts that contain <br> tags",
paper: new Paper( "<p>This is a test.<br>This is<br />another<br>test.</p>", { keyword: "test" } ),
keyphraseForms: [ [ "test" ] ],
expectedCount: 2,
expectedMarkings: [
new Mark( {
original: "This is a test.",
marked: "This is a <yoastmark class='yoast-text-mark'>test</yoastmark>.",
position: {
startOffset: 13,
endOffset: 17,
startOffsetBlock: 10,
endOffsetBlock: 14,
attributeId: "",
clientId: "",
isFirstSection: false,
} }
),
new Mark( {
original: "\nThis is\nanother\ntest.",
marked: "\nThis is\nanother\n<yoastmark class='yoast-text-mark'>test</yoastmark>.",
position: {
startOffset: 46,
endOffset: 50,
startOffsetBlock: 43,
endOffsetBlock: 47,
attributeId: "",
clientId: "",
isFirstSection: false,
} }
),
],
skip: false,
},
{
description: "can match paragraph gutenberg block",
paper: new Paper(
Expand Down Expand Up @@ -1856,6 +1891,35 @@ describe( "Test for counting the keyphrase in a text for Japanese", () => {
original: "私の猫はかわいいです。" } ) ] );
} );

it( "counts the keyphrase occurrence inside an image caption.", function() {
const mockPaper = new Paper( "<p>[caption id=\"attachment_157\" align=\"alignnone\" width=\"225\"]<img " +
"src=\"http://one.wordpress.test/wp-content/uploads/2023/07/IMG_0967_2-1-225x300.jpg\" alt=\"\" " +
"width=\"225\" height=\"300\" /> 一日一冊の本を読むのはできるかどうかやってみます。[/caption]</p>", {
locale: "ja",
keyphrase: "一冊の本を読む",
shortcodes: [
"wp_caption",
"caption",
"gallery",
"playlist" ],
} );
const keyphraseForms = [
[ "一冊" ],
[ "本" ],
[ "読む", "読み", "読ま", "読め", "読も", "読ん", "読める", "読ませ", "読ませる", "読まれ", "読まれる", "読もう" ],
];
const researcher = buildJapaneseMockResearcher( keyphraseForms, wordsCountHelper, matchWordsHelper );
buildTree( mockPaper, researcher );


expect( getKeyphraseCount( mockPaper, researcher ).count ).toBe( 1 );
expect( getKeyphraseCount( mockPaper, researcher ).markings ).toEqual( [
new Mark( {
marked: "一日<yoastmark class='yoast-text-mark'>一冊</yoastmark>の<yoastmark " +
"class='yoast-text-mark'>本</yoastmark>を<yoastmark class='yoast-text-mark'>読む</yoastmark>のはできるかどうかやってみます。",
original: "一日一冊の本を読むのはできるかどうかやってみます。" } ) ] );
} );

it( "counts/marks a string of text with multiple occurrences of the same keyphrase in it.", function() {
const mockPaper = new Paper( "<p>私の猫はかわいい猫です。</p>", { locale: "ja", keyphrase: "猫" } );
const researcher = buildJapaneseMockResearcher( [ [ "猫" ] ], wordsCountHelper, matchWordsHelper );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,21 @@ describe( "A test for getting positions of sentences", () => {
expect( getTextElementPositions( node, sentences ) ).toEqual( sentencesWithPositions );
} );

it( "should determine the correct token positions when the sentence contains a br tag", function() {
// HTML: <p>Hello<br />world!</p>.
const html = "<p>Hello<br />world!</p>";
const tree = adapt( parseFragment( html, { sourceCodeLocationInfo: true } ) );
const paragraph = tree.childNodes[ 0 ];
const tokens = [ "Hello", "\n", "world", "!" ].map( string => new Token( string ) );

const [ hello, br, world, bang ] = getTextElementPositions( paragraph, tokens, 3 );

expect( hello.sourceCodeRange ).toEqual( { startOffset: 3, endOffset: 8 } );
expect( br.sourceCodeRange ).toEqual( { startOffset: 13, endOffset: 14 } );
expect( world.sourceCodeRange ).toEqual( { startOffset: 14, endOffset: 19 } );
expect( bang.sourceCodeRange ).toEqual( { startOffset: 19, endOffset: 20 } );
} );

it( "gets the sentence positions from a node that has a code child node", function() {
// HTML: <p>Hello <code>array.push( something )</code> code!</p>
const node = new Paragraph( {}, [
Expand Down
24 changes: 24 additions & 0 deletions packages/yoastseo/spec/parse/build/private/tokenizeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,30 @@ describe( "A test for the tokenize function",
name: "#document-fragment",
} );
} );

it( "should correctly tokenize a paragraph with single br tags", function() {
const mockPaper = new Paper( "<p>This is a sentence.<br />This is<br>another sentence.</p>" );
const mockResearcher = new EnglishResearcher( mockPaper );
const languageProcessor = new LanguageProcessor( mockResearcher );
buildTreeNoTokenize( mockPaper );
const result = tokenize( mockPaper.getTree(), languageProcessor );
const sentences = result.childNodes[ 0 ].sentences;
expect( sentences.length ).toEqual( 2 );
const firstSentence = sentences[ 0 ];
expect( firstSentence.text ).toEqual( "This is a sentence." );
expect( firstSentence.sourceCodeRange ).toEqual( { startOffset: 3, endOffset: 22 } );
expect( firstSentence.tokens.length ).toEqual( 8 );
const secondSentence = sentences[ 1 ];
expect( secondSentence.text ).toEqual( "\nThis is\nanother sentence." );
expect( secondSentence.sourceCodeRange ).toEqual( { startOffset: 27, endOffset: 56 } );
expect( secondSentence.tokens.length ).toEqual( 9 );
const [ br1, this1, , is1, br2, another1, , , ] = secondSentence.tokens;
expect( br1.sourceCodeRange ).toEqual( { startOffset: 27, endOffset: 28 } );
expect( this1.sourceCodeRange ).toEqual( { startOffset: 28, endOffset: 32 } );
expect( is1.sourceCodeRange ).toEqual( { startOffset: 33, endOffset: 35 } );
expect( br2.sourceCodeRange ).toEqual( { startOffset: 38, endOffset: 39 } );
expect( another1.sourceCodeRange ).toEqual( { startOffset: 39, endOffset: 46 } );
} );
} );

describe( "A test for tokenizing a Japanese sentence", function() {
Expand Down
11 changes: 11 additions & 0 deletions packages/yoastseo/spec/parse/traverse/innerTextSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ describe( "A test for innerText", () => {
expect( searchResult ).toEqual( expected );
} );

it( "should consider break tags to be line breaks", function() {
// Matsuo Bashō's "old pond".
paper._text = "<p>old pond<br />frog leaps in<br>water's sound</p>";
const tree = build( paper, languageProcessor );

const searchResult = innerText( tree );
const expected = "old pond\nfrog leaps in\nwater's sound";

expect( searchResult ).toEqual( expected );
} );

it( "should return an empty string when presented an empty node", function() {
const tree = new Node( "" );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ describe( "A test for marking the keyphrase", function() {
const keyphraseDensityAssessment = new KeyphraseDensityAssessment();
const paper = new Paper( "<p><img class='size-medium wp-image-33' src='http://basic.wordpress.test/wp-content/uploads/2021/08/" +
"cat-3957861_1280-211x300.jpeg' alt='a different cat with toy' width='211' height='300'></img> " +
"A flamboyant cat with a toy<br/>\n" +
"A flamboyant cat with a toy<br/>" +
"</p>",
{ keyword: "cat toy" } );
const researcher = new EnglishResearcher( paper );
Expand Down
Loading

0 comments on commit ab4b3f1

Please sign in to comment.