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

Yoast / wordpress-seo / 7adc35280975ee18a31269fb7d485dd07fa7c76a

08 Jan 2026 01:45PM UTC coverage: 51.85%. First build
7adc35280975ee18a31269fb7d485dd07fa7c76a

push

github

thijsoo
Merge branch 'trunk' of github.com:Yoast/wordpress-seo into feature/schema_aggregator

# Conflicts:
#	inc/options/class-wpseo-option-wpseo.php
#	packages/js/src/settings/routes/site-features.js

8774 of 16273 branches covered (53.92%)

Branch coverage included in aggregate %.

121 of 477 new or added lines in 60 files covered. (25.37%)

32980 of 64256 relevant lines covered (51.33%)

44874.43 hits per line

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

0.0
/packages/js/src/settings/components/schema-api-integrations-section.js
1
import { LockOpenIcon } from "@heroicons/react/outline";
2
import { CheckIcon, XIcon } from "@heroicons/react/solid";
3
import { __, sprintf } from "@wordpress/i18n";
4
import { Button } from "@yoast/ui-library";
5
import PropTypes from "prop-types";
6
import { safeCreateInterpolateElement } from "../../helpers/i18n";
7
import { useSelectSettings } from "../hooks";
8

9
/**
10
 * Integration status component.
11
 *
12
 * @param {Object} props The props.
13
 * @param {boolean} props.isActive Whether the integration is active.
14
 * @param {boolean} [props.isPremiumRequired] Whether premium is required.
15
 * @param {boolean} [props.hasPremium] Whether the user has premium.
16
 * @param {string} [props.upsellLink] The upsell link.
17
 * @param {string} [props.upsellLabel] The upsell button label.
18
 * @returns {JSX.Element} The status element.
19
 */
20

21
// eslint-disable-next-line complexity
NEW
22
const IntegrationStatus = ( {
×
23
        isActive,
24
        isPremiumRequired = false,
×
25
        hasPremium = false,
×
26
        upsellLink = "",
×
27
        upsellLabel = "",
×
28
} ) => {
NEW
29
        if ( isPremiumRequired && ! hasPremium ) {
×
NEW
30
                return (
×
31
                        <Button
32
                                as="a"
33
                                variant="upsell"
34
                                size="small"
35
                                href={ upsellLink }
36
                                target="_blank"
37
                                // rel for security reasons and backwards compatibility with older browsers
38
                                rel="noopener"
39
                                className="yst-gap-1"
40
                        >
41
                                <LockOpenIcon className="yst-w-4 yst-h-4 yst-text-amber-900" />
42
                                { upsellLabel }
43
                        </Button>
44
                );
45
        }
46

NEW
47
        if ( isActive ) {
×
NEW
48
                return (
×
49
                        <span className="yst-flex yst-items-center yst-gap-1.5">
50
                                <CheckIcon className="yst-w-5 yst-h-5 yst-text-green-500" />
51
                                <span className="yst-text-green-600 yst-font-medium">{ __( "Integration active", "wordpress-seo" ) }</span>
52
                        </span>
53
                );
54
        }
55

NEW
56
        return (
×
57
                <span className="yst-flex yst-items-center yst-gap-1.5">
58
                        <XIcon className="yst-w-5 yst-h-5 yst-text-red-500" />
59
                        <span className="yst-text-slate-600 yst-font-medium">{ __( "Plugin not detected", "wordpress-seo" ) }</span>
60
                </span>
61
        );
62
};
63

NEW
64
IntegrationStatus.propTypes = {
×
65
        isActive: PropTypes.bool.isRequired,
66
        isPremiumRequired: PropTypes.bool,
67
        hasPremium: PropTypes.bool,
68
        upsellLink: PropTypes.string,
69
        upsellLabel: PropTypes.string,
70
};
71

72
/**
73
 * WooCommerce integration status component.
74
 *
75
 * @param {Object} props The props.
76
 * @param {boolean} props.isPrerequisiteActive Whether WooCommerce is active.
77
 * @param {boolean} props.isActive Whether Yoast WooCommerce SEO is active.
78
 * @param {boolean} props.isInstalled Whether Yoast WooCommerce SEO is installed.
79
 * @param {string} props.activationLink The activation link.
80
 * @param {string} props.upsellLink The upsell link.
81
 * @returns {JSX.Element} The status element.
82
 */
NEW
83
const WooCommerceStatus = ( {
×
84
        isPrerequisiteActive,
85
        isActive,
86
        isInstalled,
87
        activationLink,
88
        upsellLink,
89
} ) => {
NEW
90
        if ( ! isPrerequisiteActive ) {
×
NEW
91
                return (
×
92
                        <span className="yst-flex yst-items-center yst-gap-1.5">
93
                                <XIcon className="yst-w-5 yst-h-5 yst-text-red-500" />
94
                                <span className="yst-text-slate-600 yst-font-medium">{ __( "Plugin not detected", "wordpress-seo" ) }</span>
95
                        </span>
96
                );
97
        }
98

NEW
99
        if ( isActive ) {
×
NEW
100
                return (
×
101
                        <span className="yst-flex yst-items-center yst-gap-1.5">
102
                                <CheckIcon className="yst-w-5 yst-h-5 yst-text-green-500" />
103
                                <span className="yst-text-green-600 yst-font-medium">{ __( "Integration active", "wordpress-seo" ) }</span>
104
                        </span>
105
                );
106
        }
107

NEW
108
        if ( isInstalled ) {
×
NEW
109
                return (
×
110
                        <Button
111
                                as="a"
112
                                variant="secondary"
113
                                size="small"
114
                                href={ activationLink }
115
                        >
116
                                { sprintf(
117
                                        /* translators: %s: Yoast WooCommerce SEO */
118
                                        __( "Activate %s", "wordpress-seo" ),
119
                                        "Yoast WooCommerce SEO"
120
                                ) }
121
                        </Button>
122
                );
123
        }
124

NEW
125
        return (
×
126
                <Button
127
                        as="a"
128
                        variant="upsell"
129
                        size="small"
130
                        href={ upsellLink }
131
                        target="_blank"
132
                        rel="noopener"
133
                        className="yst-gap-1"
134
                >
135
                        <LockOpenIcon className="yst-w-4 yst-h-4 yst-text-amber-900" />
136
                        { sprintf(
137
                                /* translators: %s: WooCommerce SEO */
138
                                __( "Unlock with %s", "wordpress-seo" ),
139
                                "WooCommerce SEO"
140
                        ) }
141
                </Button>
142
        );
143
};
144

NEW
145
WooCommerceStatus.propTypes = {
×
146
        isPrerequisiteActive: PropTypes.bool.isRequired,
147
        isActive: PropTypes.bool.isRequired,
148
        isInstalled: PropTypes.bool.isRequired,
149
        activationLink: PropTypes.string.isRequired,
150
        upsellLink: PropTypes.string.isRequired,
151
};
152

153
/**
154
 * Schema API integrations section component.
155
 *
156
 * @param {Object} props The props.
157
 * @param {boolean} [props.isDisabled] Whether the section list is disabled.
158
 * @returns {JSX.Element} The section element.
159
 */
NEW
160
const SchemaApiIntegrationsSection = ( { isDisabled = false } ) => {
×
NEW
161
        const schemaApiIntegrations = useSelectSettings( "selectSchemaApiIntegrations", [] );
×
NEW
162
        const hasPremium = useSelectSettings( "selectPreference", [], "isPremium" );
×
NEW
163
        const woocommerceSeoUpsellLink = useSelectSettings( "selectLink", [], "https://yoa.st/integrations-get-woocommerce" );
×
NEW
164
        const eddUpsellLink = useSelectSettings( "selectLink", [], "https://yoa.st/get-edd-integration" );
×
165

NEW
166
        const description = safeCreateInterpolateElement(
×
167
                sprintf(
168
                        /* translators: %1$s and %2$s are replaced by opening and closing <a> tags. */
169
                        __( "With Yoast SEO's Schema API, developers can easily connect custom content types to our rich Schema graph. %1$sSee our integrations page for details%2$s.", "wordpress-seo" ),
170
                        "<a>",
171
                        "</a>"
172
                ), {
173
                        // eslint-disable-next-line jsx-a11y/anchor-has-content
174
                        a: <a href="admin.php?page=wpseo_integrations" />,
175
                }
176
        );
177

NEW
178
        const integrations = [
×
179
                {
180
                        slug: "tec",
181
                        name: __( "The Events Calendar", "wordpress-seo" ),
182
                },
183
                {
184
                        slug: "ssp",
185
                        name: __( "Seriously Simple Podcasting", "wordpress-seo" ),
186
                },
187
                {
188
                        slug: "wp-recipe-maker",
189
                        name: __( "WP Recipe Maker", "wordpress-seo" ),
190
                },
191
                {
192
                        slug: "woocommerce",
193
                        name: __( "Yoast WooCommerce SEO", "wordpress-seo" ),
194
                },
195
                {
196
                        slug: "edd",
197
                        name: __( "Easy Digital Downloads", "wordpress-seo" ),
198
                },
199
        ];
200

201
        /**
202
         * Renders the status for an integration.
203
         *
204
         * @param {Object} integration The integration object.
205
         * @param {Object} data The integration data.
206
         * @returns {JSX.Element} The status element.
207
         */
208
        // eslint-disable-next-line complexity
NEW
209
        const renderIntegrationStatus = ( integration, data ) => {
×
210
                // When schema is disabled programmatically, show the disabled status for all integrations.
NEW
211
                if ( isDisabled ) {
×
NEW
212
                        return (
×
213
                                <span className="yst-text-red-600 yst-font-medium">{ __( "Schema Framework disabled", "wordpress-seo" ) }</span>
214
                        );
215
                }
216

217
                // Handles the WooCommerce plugin prerequisites.
NEW
218
                if ( integration.slug === "woocommerce" ) {
×
NEW
219
                        return (
×
220
                                <WooCommerceStatus
221
                                        isPrerequisiteActive={ data.isPrerequisiteActive || false }
×
222
                                        isActive={ data.isActive || false }
×
223
                                        isInstalled={ data.isInstalled || false }
×
224
                                        activationLink={ data.activationLink || "" }
×
225
                                        upsellLink={ woocommerceSeoUpsellLink }
226
                                />
227
                        );
228
                }
229

230
                // Easy Digital Downloads integration requires Yoast SEO Premium to be active.
NEW
231
                if ( integration.slug === "edd" ) {
×
NEW
232
                        return (
×
233
                                <IntegrationStatus
234
                                        isActive={ data.isActive || false }
×
235
                                        isPremiumRequired={ true }
236
                                        hasPremium={ hasPremium || data.isPremium || false }
×
237
                                        upsellLink={ eddUpsellLink }
238
                                        upsellLabel={ __( "Unlock with Premium", "wordpress-seo" ) }
239
                                />
240
                        );
241
                }
242

243
                // Default: plugin detection (active or not detected).
NEW
244
                return (
×
245
                        <IntegrationStatus
246
                                isActive={ data.isActive || false }
×
247
                        />
248
                );
249
        };
250

NEW
251
        return (
×
252
                <fieldset className="yst-min-w-0">
253
                        <div className="yst-flex yst-flex-col sm:yst-flex-row yst-items-start yst-gap-6 yst-w-3/4">
254
                                <div className="sm:yst-shrink-0 yst-max-w-xs">
255
                                        <span className="yst-block yst-font-medium yst-text-slate-800">{ __( "Schema API integrations", "wordpress-seo" ) }</span>
256
                                        <p className="yst-mt-1">{ description }</p>
257
                                </div>
258
                                <div className={ `yst-divide-y yst-divide-slate-200 yst-grow${ isDisabled ? " yst-opacity-50 yst-pointer-events-none" : "" }` }>
×
259
                                        { integrations.map( ( integration ) => {
NEW
260
                                                const data = schemaApiIntegrations[ integration.slug ] || {};
×
NEW
261
                                                return (
×
262
                                                        <div
263
                                                                key={ integration.slug }
264
                                                                className="yst-py-4 first:yst-pt-0"
265
                                                        >
266
                                                                <span className="yst-block yst-font-medium yst-text-slate-800">{ integration.name }</span>
267
                                                                <div className="yst-mt-1">
268
                                                                        { renderIntegrationStatus( integration, data ) }
269
                                                                </div>
270
                                                        </div>
271
                                                );
272
                                        } ) }
273
                                </div>
274
                        </div>
275
                </fieldset>
276
        );
277
};
278

NEW
279
SchemaApiIntegrationsSection.propTypes = {
×
280
        isDisabled: PropTypes.bool,
281
};
282

283
export { SchemaApiIntegrationsSection };
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