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

Yoast / wordpress-seo / 5ccd3c5c2e9cc79d61b159392fc426e5fdbc715b

09 Mar 2026 08:28AM UTC coverage: 53.891% (-0.02%) from 53.915%
5ccd3c5c2e9cc79d61b159392fc426e5fdbc715b

push

github

web-flow
Merge pull request #23015 from Yoast/1070-task-list-cta-of-the-seo-or-readability-child-tasks-land-on-the-post-seo-readability-analysis-opened

1070 task list cta of the seo or readability child tasks land on the post seo readability analysis opened

9018 of 16605 branches covered (54.31%)

Branch coverage included in aggregate %.

16 of 40 new or added lines in 8 files covered. (40.0%)

3 existing lines in 2 files now uncovered.

34247 of 63678 relevant lines covered (53.78%)

46983.99 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
         *
52
         * @returns {wp.Element} The Readability Analysis results.
53
         */
54
        renderResults( upsellResults ) {
55
                const highlightingUpsellLink = "shortlinks.upsell.sidebar.highlighting_readability_analysis";
×
56

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

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

100
                link = addQueryArgs( link, { context: locationContext } );
×
101

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

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

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

134

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

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

162

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

171
                if ( isNil( this.props.overallScore ) ) {
×
172
                        score.className = "loading";
×
173
                }
174

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

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

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

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

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

252
        return {
×
253
                ...getReadabilityResults(),
254
                marksButtonStatus: getMarkButtonStatus(),
255
                isElementor: getIsElementorEditor(),
256
                isAiFeatureEnabled: getIsAiFeatureEnabled(),
257
                isTerm: getIsTerm(),
258
        };
259
} )( 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