• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 6bc35a0477f099baadefeb350fe5fba3b65c53f0

26 Mar 2026 11:41AM UTC coverage: 53.504% (+0.03%) from 53.474%
6bc35a0477f099baadefeb350fe5fba3b65c53f0

Pull #23102

github

leonidasmi
Merge branch 'trunk' into feature/task-list-phase-3
Pull Request #23102: Task List Phase 3

9052 of 16649 branches covered (54.37%)

Branch coverage included in aggregate %.

142 of 201 new or added lines in 22 files covered. (70.65%)

5 existing lines in 3 files now uncovered.

34478 of 64710 relevant lines covered (53.28%)

46486.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/js/src/components/contentAnalysis/ReadabilityAnalysis.js
1
/* global wpseoAdminL10n */
2
/* External components */
3
import { Component, Fragment } from "@wordpress/element";
4
import { withSelect } from "@wordpress/data";
5
import PropTypes from "prop-types";
6
import styled from "styled-components";
7
import { __, sprintf } from "@wordpress/i18n";
8
import { isNil } from "lodash";
9

10
/* Internal components */
11
import ScoreIconPortal from "../portals/ScoreIconPortal";
12
import Results from "../../containers/Results";
13
import Collapsible from "../SidebarCollapsible";
14
import getIndicatorForScore from "../../analysis/getIndicatorForScore";
15
import { getIconForScore } from "./mapResults";
16
import { LocationConsumer, RootContext } from "@yoast/externals/contexts";
17
import HelpLink from "../HelpLink";
18
import ReadabilityResultsPortal from "../portals/ReadabilityResultsPortal";
19
import { isWordComplexitySupported } from "../../helpers/assessmentUpsellHelpers";
20
import { addQueryArgs, getQueryArg } from "@wordpress/url";
21
import getL10nObject from "../../analysis/getL10nObject";
22
import AIOptimizeButton from "../../ai-optimizer/components/ai-optimize-button";
23
import { shouldRenderAIOptimizeButton } from "../../helpers/shouldRenderAIOptimizeButton";
24

25
// Capture at module-load time, before `openGeneralSidebar` causes WordPress to replace the URL.
NEW
26
const initialYoastTab = getQueryArg( window.location.href, "yoast-tab" );
×
27

UNCOV
28
const AnalysisHeader = styled.span`
×
29
        font-size: 1em;
30
        font-weight: bold;
31
        margin: 0 0 8px;
32
        display: block;
33
`;
34

35
const ReadabilityResultsTabContainer = styled.div`
×
36
        padding: 16px;
37
`;
38

39
const StyledHelpLink = styled( HelpLink )`
×
40
        margin: -8px 0 -4px 4px;
41
`;
42

43
/**
44
 * Redux container for the readability analysis.
45
 */
46
class ReadabilityAnalysis extends Component {
47
        /**
48
         * Renders the Readability Analysis results.
49
         *
50
         * @param {Array} upsellResults The array of upsell results.
51
         * @param {string} location Where this component is rendered (metabox or sidebar).
52
         *
53
         * @returns {wp.Element} The Readability Analysis results.
54
         */
55
        renderResults( upsellResults, location ) {
56
                const highlightingUpsellLink = "shortlinks.upsell.sidebar.highlighting_readability_analysis";
×
57

58
                return (
×
59
                        <Fragment>
60
                                <AnalysisHeader>
61
                                        { __( "Analysis results", "wordpress-seo" ) }
62
                                        <StyledHelpLink
63
                                                href={ wpseoAdminL10n[ "shortlinks.readability_analysis_info" ] }
64
                                                className="dashicons"
65
                                        >
66
                                                <span className="screen-reader-text">
67
                                                        {
68
                                                                /* translators: Hidden accessibility text. */
69
                                                                __( "Learn more about the readability analysis", "wordpress-seo" )
70
                                                        }
71
                                                </span>
72
                                        </StyledHelpLink>
73
                                </AnalysisHeader>
74
                                <Results
75
                                        results={ this.props.results }
76
                                        upsellResults={ upsellResults }
77
                                        marksButtonClassName="yoast-tooltip yoast-tooltip-w"
78
                                        marksButtonStatus={ this.props.marksButtonStatus }
79
                                        location={ location }
80
                                        id={ location ? `yoast-readability-analysis-results-${ location }` : "" }
×
81
                                        highlightingUpsellLink={ highlightingUpsellLink }
82
                                        shouldUpsellHighlighting={ this.props.shouldUpsellHighlighting }
83
                                        renderAIOptimizeButton={ this.renderAIOptimizeButton }
84
                                />
85
                        </Fragment>
86
                );
87
        }
88

89
        /**
90
         * Returns the list of results used to upsell the user to Premium.
91
         *
92
         * @param {string} location                 Where this component is rendered (metabox or sidebar).
93
         * @param {string} locationContext         In which editor this component is rendered.
94
         *
95
         * @returns {Array} The upsell results.
96
         */
97
        getUpsellResults( location, locationContext ) {
98
                let link = wpseoAdminL10n[ "shortlinks.upsell.metabox.word_complexity" ];
×
99
                if ( location === "sidebar" ) {
×
100
                        link = wpseoAdminL10n[ "shortlinks.upsell.sidebar.word_complexity" ];
×
101
                }
102

103
                link = addQueryArgs( link, { context: locationContext } );
×
104

105
                /*
106
                 * We don't show the upsell for Word complexity assessment if it's not supported for the current locale.
107
                 */
108
                if ( ! isWordComplexitySupported() ) {
×
109
                        return [];
×
110
                }
111

112
                const wordComplexityUpsellText = sprintf(
×
113
                        /* Translators: %1$s is a span tag that adds styling to 'Word complexity', %2$s is a closing span tag.
114
                           %3$s is an anchor tag with a link to yoast.com, %4$s is a closing anchor tag.*/
115
                        __(
116
                                "%1$sWord complexity%2$s: Is your vocabulary suited for a larger audience? %3$sYoast SEO Premium will tell you!%4$s",
117
                                "wordpress-seo"
118
                        ),
119
                        "<span style='text-decoration: underline'>",
120
                        "</span>",
121
                        `<a href="${ link }" data-action="load-nfd-ctb" data-ctb-id="f6a84663-465f-4cb5-8ba5-f7a6d72224b2" target="_blank">`,
122
                        "</a>"
123
                );
124

125
                return [
×
126
                        {
127
                                score: 0,
128
                                rating: "upsell",
129
                                hasMarks: false,
130
                                id: "wordComplexity",
131
                                text: wordComplexityUpsellText,
132
                                markerId: "wordComplexity",
133
                        },
134
                ];
135
        }
136

137

138
        /**
139
         * Renders the Yoast AI Optimize button.
140
         * The button is shown when:
141
         * - The assessment can be fixed through Yoast AI Optimize.
142
         * - The AI feature is enabled (for Yoast SEO Premium users; for Free users, the button is shown with an upsell).
143
         * - We are in the block editor or classic editor.
144
         * - We are not in the Elementor editor, nor in the Elementor in-between screen.
145
         * - We are not in a Taxonomy.
146
         *
147
         * @param {boolean} hasAIFixes Whether the assessment can be fixed through Yoast AI Optimize.
148
         * @param {string} id The assessment ID.
149
         *
150
         * @returns {void|JSX.Element} The AI Optimize button, or nothing if the button should not be shown.
151
         */
152
        renderAIOptimizeButton = ( hasAIFixes, id ) => {
×
153
                const { isElementor, isAiFeatureEnabled, isTerm } = this.props;
×
154
                const isPremium = getL10nObject().isPremium;
×
155

156
                // Don't show the button if the AI feature is not enabled for Yoast SEO Premium users.
157
                if ( isPremium && ! isAiFeatureEnabled ) {
×
158
                        return;
×
159
                }
160
                const shouldRenderAIButton = shouldRenderAIOptimizeButton( hasAIFixes, isElementor, isTerm );
×
161
                // Show the button if the assessment can be fixed through Yoast AI Optimize, and we are not in the Elementor editor, or Taxonomy.
162
                return shouldRenderAIButton && ( <AIOptimizeButton id={ id } isPremium={ isPremium } /> );
×
163
        };
164

165

166
        /**
167
         * Renders the Readability Analysis component.
168
         *
169
         * @returns {wp.Element} The Readability Analysis component.
170
         */
171
        render() {
172
                const score = getIndicatorForScore( this.props.overallScore );
×
173

174
                if ( isNil( this.props.overallScore ) ) {
×
175
                        score.className = "loading";
×
176
                }
177

178
                return (
×
179
                        <LocationConsumer>
180
                                { location => {
181
                                        return (
×
182
                                                <RootContext.Consumer>
183
                                                        { ( { locationContext } ) => {
184
                                                                let upsellResults = [];
×
185
                                                                if ( this.props.shouldUpsell ) {
×
186
                                                                        upsellResults = this.getUpsellResults( location, locationContext );
×
187
                                                                }
188
                                                                if ( location === "sidebar" ) {
×
NEW
189
                                                                        const initialIsOpen = initialYoastTab === "readability";
×
UNCOV
190
                                                                        return (
×
191
                                                                                <Collapsible
192
                                                                                        title={ __( "Readability analysis", "wordpress-seo" ) }
193
                                                                                        titleScreenReaderText={ score.screenReaderReadabilityText }
194
                                                                                        prefixIcon={ getIconForScore( score.className ) }
195
                                                                                        prefixIconCollapsed={ getIconForScore( score.className ) }
196
                                                                                        id={ `yoast-readability-analysis-collapsible-${ location }` }
197
                                                                                        initialIsOpen={ initialIsOpen }
198
                                                                                >
199
                                                                                        { this.renderResults( upsellResults, location ) }
200
                                                                                </Collapsible>
201
                                                                        );
202
                                                                }
203

204
                                                                if ( location === "metabox" ) {
×
205
                                                                        return (
×
206
                                                                                <ReadabilityResultsPortal target="wpseo-metabox-readability-root">
207
                                                                                        <ReadabilityResultsTabContainer>
208
                                                                                                <ScoreIconPortal
209
                                                                                                        target="wpseo-readability-score-icon"
210
                                                                                                        scoreIndicator={ score.className }
211
                                                                                                />
212
                                                                                                { this.renderResults( upsellResults, location ) }
213
                                                                                        </ReadabilityResultsTabContainer>
214
                                                                                </ReadabilityResultsPortal>
215
                                                                        );
216
                                                                }
217
                                                        } }
218
                                                </RootContext.Consumer>
219
                                        );
220
                                } }
221
                        </LocationConsumer>
222
                );
223
        }
224
}
225

226
ReadabilityAnalysis.propTypes = {
×
227
        results: PropTypes.array.isRequired,
228
        marksButtonStatus: PropTypes.string.isRequired,
229
        overallScore: PropTypes.number,
230
        shouldUpsell: PropTypes.bool,
231
        shouldUpsellHighlighting: PropTypes.bool,
232
        isAiFeatureEnabled: PropTypes.bool,
233
        isElementor: PropTypes.bool,
234
        isTerm: PropTypes.bool,
235
};
236

237
ReadabilityAnalysis.defaultProps = {
×
238
        overallScore: null,
239
        shouldUpsell: false,
240
        shouldUpsellHighlighting: false,
241
        isAiFeatureEnabled: false,
242
        isElementor: false,
243
        isTerm: false,
244
};
245

246
export default withSelect( select => {
247
        const {
248
                getReadabilityResults,
249
                getMarkButtonStatus,
250
                getIsElementorEditor,
251
                getIsAiFeatureEnabled,
252
                getIsTerm,
253
        } = select( "yoast-seo/editor" );
×
254

255
        return {
×
256
                ...getReadabilityResults(),
257
                marksButtonStatus: getMarkButtonStatus(),
258
                isElementor: getIsElementorEditor(),
259
                isAiFeatureEnabled: getIsAiFeatureEnabled(),
260
                isTerm: getIsTerm(),
261
        };
262
} )( ReadabilityAnalysis );
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc