Skip to content
Draft
1 change: 1 addition & 0 deletions admin/tracking/class-tracking-settings-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/**
* The options that need to be anonymized before they can be sent elsewhere.
*
* @var array All of the option_names which need to be

Check failure on line 16 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@var annotation of property \WPSEO_Tracking_Settings_Data::$anonymous_settings does not specify type hint for its items.

Check failure on line 16 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@var annotation of property \WPSEO_Tracking_Settings_Data::$anonymous_settings does not specify type hint for its items.
* anonymized before they can be sent elsewhere.
*/
private $anonymous_settings = [
Expand Down Expand Up @@ -73,7 +73,7 @@
/**
* The options we want to track.
*
* @var array The option_names for the options we want to track.

Check failure on line 76 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@var annotation of property \WPSEO_Tracking_Settings_Data::$include_list does not specify type hint for its items.

Check failure on line 76 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@var annotation of property \WPSEO_Tracking_Settings_Data::$include_list does not specify type hint for its items.
*/
private $include_list = [
'ms_defaults_set',
Expand Down Expand Up @@ -245,12 +245,13 @@
'llms_txt_selection_mode',
'configuration_finished_steps',
'enable_task_list',
'enable_schema',
];

/**
* Returns the collection data.
*
* @return array The collection data.

Check failure on line 254 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@return annotation of method \WPSEO_Tracking_Settings_Data::get() does not specify type hint for items of its traversable return value.

Check failure on line 254 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@return annotation of method \WPSEO_Tracking_Settings_Data::get() does not specify type hint for items of its traversable return value.
*/
public function get() {
/**
Expand All @@ -272,9 +273,9 @@
/**
* Anonimizes the WPSEO_Options array by replacing all $anonymous_settings values to 'used'.
*
* @param array $settings The settings.

Check failure on line 276 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@param annotation of method \WPSEO_Tracking_Settings_Data::anonymize_settings() does not specify type hint for items of its traversable parameter $settings.

Check failure on line 276 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@param annotation of method \WPSEO_Tracking_Settings_Data::anonymize_settings() does not specify type hint for items of its traversable parameter $settings.
*
* @return array The anonymized settings.

Check failure on line 278 in admin/tracking/class-tracking-settings-data.php

View workflow job for this annotation

GitHub Actions / Check code style

@return annotation of method \WPSEO_Tracking_Settings_Data::anonymize_settings() does not specify type hint for items of its traversable return value.
*/
private function anonymize_settings( $settings ) {
foreach ( $this->anonymous_settings as $setting ) {
Expand Down
1 change: 1 addition & 0 deletions images/icon-schema.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions inc/options/class-wpseo-option-wpseo.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
'default_seo_meta_desc' => [],
'first_activated_by' => 0,
'enable_task_list' => true,
'enable_schema' => true,
];

/**
Expand Down Expand Up @@ -549,6 +550,7 @@
* 'google_site_kit_feature_enabled',
* 'enable_llms_txt',
* 'enable_task_list',
* 'enable_schema',
* and most of the feature variables.
*/
default:
Expand Down Expand Up @@ -620,6 +622,7 @@
'google_site_kit_feature_enabled' => false,
'enable_llms_txt' => false,
'enable_task_list' => false,
'enable_schema' => false,
];

// We can reuse this logic from the base class with the above defaults to parse with the correct feature values.
Expand Down Expand Up @@ -669,7 +672,7 @@
*
* @return array Cleaned option.
*/
protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {

Check warning on line 675 in inc/options/class-wpseo-option-wpseo.php

View workflow job for this annotation

GitHub Actions / Check code style

Unused function parameter $all_old_option_values.

Check warning on line 675 in inc/options/class-wpseo-option-wpseo.php

View workflow job for this annotation

GitHub Actions / Check code style

Unused function parameter $current_version.

Check warning on line 675 in inc/options/class-wpseo-option-wpseo.php

View workflow job for this annotation

GitHub Actions / Check code style

Unused function parameter $all_old_option_values.

Check warning on line 675 in inc/options/class-wpseo-option-wpseo.php

View workflow job for this annotation

GitHub Actions / Check code style

Unused function parameter $current_version.
// Deal with value change from text string to boolean.
$value_change = [
'ignore_search_engines_discouraged_notice',
Expand Down
17 changes: 14 additions & 3 deletions packages/js/src/integrations-page/plugin-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,37 @@ import { __ } from "@wordpress/i18n";
import { PropTypes } from "prop-types";
import { SimpleIntegration } from "./simple-integration";

// Flag to check if the Schema Framework is enabled.
// eslint-disable-next-line dot-notation
const isSchemaFrameworkEnabled = Boolean( window.wpseoIntegrationsData[ "schema_framework_enabled" ] );

/**
* Represents an integration.
*
* @param {Object} integration The integration.
* @param {boolean} [isActive=true] The integration state.
* @param {boolean} [isSchemaAPIIntegration=false] Whether this is a Schema API integration.
*
* @returns {JSX.Element} A card representing an integration.
*/
export const PluginIntegration = ( { integration, isActive = true } ) => {
export const PluginIntegration = ( { integration, isActive = true, isSchemaAPIIntegration = false } ) => {
const isSchemaFrameworkDisabled = isSchemaAPIIntegration && ! isSchemaFrameworkEnabled;

return (
<SimpleIntegration
integration={ integration }
isActive={ isActive }
>
{ isActive && <Fragment>
{ isSchemaFrameworkDisabled && <Fragment>
<span className="yst-text-red-600 yst-font-medium">{ __( "Schema Framework disabled", "wordpress-seo" ) }</span>
</Fragment> }
{ ! isSchemaFrameworkDisabled && isActive && <Fragment>
<span className="yst-text-slate-700 yst-font-medium">{ __( "Integration active", "wordpress-seo" ) }</span>
<CheckIcon
className="yst-h-5 yst-w-5 yst-text-green-400 yst-flex-shrink-0"
/>
</Fragment> }
{ ! isActive && <Fragment>
{ ! isSchemaFrameworkDisabled && ! isActive && <Fragment>
<span className="yst-text-slate-700 yst-font-medium">
{
__( "Plugin not detected", "wordpress-seo" )
Expand All @@ -49,4 +59,5 @@ PluginIntegration.propTypes = {
isNew: PropTypes.bool,
} ).isRequired,
isActive: PropTypes.bool,
isSchemaAPIIntegration: PropTypes.bool,
};
2 changes: 2 additions & 0 deletions packages/js/src/integrations-page/schema-api-integrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const SchemaAPIIntegrations = [
key={ index }
integration={ integration }
isActive={ getInitialState( integration ) }
isSchemaAPIIntegration={ true }
/>
);
} ),
Expand All @@ -164,6 +165,7 @@ SchemaAPIIntegrations.push(
isPrerequisiteActive={ Boolean( window.wpseoIntegrationsData[ "woocommerce_active" ] ) }
upsellLink={ window.wpseoIntegrationsData[ "woocommerce_seo_upsell_url" ] }
activationLink={ window.wpseoIntegrationsData[ "woocommerce_seo_activate_url" ] }
isSchemaAPIIntegration={ true }
/>
);
/* eslint-enable dot-notation */
Expand Down
20 changes: 16 additions & 4 deletions packages/js/src/integrations-page/woocommerce-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import { Button } from "@yoast/ui-library";
import { PropTypes } from "prop-types";
import { SimpleIntegration } from "./simple-integration";

// Flag to check if the Schema Framework is enabled.
// eslint-disable-next-line dot-notation
const isSchemaFrameworkEnabled = Boolean( window.wpseoIntegrationsData[ "schema_framework_enabled" ] );

/**
* @param {Object} integration The integration object.
* @param {boolean} [isActive=true] Whether the integration is active.
* @param {boolean} [isInstalled=true] Whether the integration is installed.
* @param {boolean} [isPrerequisiteActive=true] Whether the prerequisite plugin is active.
* @param {string} activationLink The URL to activate Yoast WooCommerce SEO.
* @param {boolean} [isSchemaAPIIntegration=false] Whether this is a Schema API integration.
* @returns {JSX.Element} A card representing an integration.
*/
export const WoocommerceIntegration = ( {
Expand All @@ -21,13 +26,19 @@ export const WoocommerceIntegration = ( {
isInstalled = true,
isPrerequisiteActive = true,
activationLink,
isSchemaAPIIntegration = false,
} ) => {
const isSchemaFrameworkDisabled = isSchemaAPIIntegration && ! isSchemaFrameworkEnabled;

return (
<SimpleIntegration
integration={ integration }
isActive={ isActive }
>
{ ! isPrerequisiteActive && <Fragment>
{ isSchemaFrameworkDisabled && <Fragment>
<span className="yst-text-red-600 yst-font-medium">{ __( "Schema Framework disabled", "wordpress-seo" ) }</span>
</Fragment> }
{ ! isSchemaFrameworkDisabled && ! isPrerequisiteActive && <Fragment>
<span className="yst-text-slate-700 yst-font-medium">
{
__( "Plugin not detected", "wordpress-seo" )
Expand All @@ -37,13 +48,13 @@ export const WoocommerceIntegration = ( {
className="yst-h-5 yst-w-5 yst-text-red-500 yst-flex-shrink-0"
/>
</Fragment> }
{ isPrerequisiteActive && isActive && <Fragment>
{ ! isSchemaFrameworkDisabled && isPrerequisiteActive && isActive && <Fragment>
<span className="yst-text-slate-700 yst-font-medium">{ __( "Integration active", "wordpress-seo" ) }</span>
<CheckIcon
className="yst-h-5 yst-w-5 yst-text-green-400 yst-flex-shrink-0"
/>
</Fragment> }
{ isPrerequisiteActive && ! isActive && isInstalled && <Fragment>
{ ! isSchemaFrameworkDisabled && isPrerequisiteActive && ! isActive && isInstalled && <Fragment>
<Button
id={ `${ integration.name }-upsell-button` }
type="button"
Expand All @@ -61,7 +72,7 @@ export const WoocommerceIntegration = ( {
}
</Button>
</Fragment> }
{ isPrerequisiteActive && ! isActive && ! isInstalled && <Fragment>
{ ! isSchemaFrameworkDisabled && isPrerequisiteActive && ! isActive && ! isInstalled && <Fragment>
<Button
id={ `${ integration.name }-upsell-button` }
type="button"
Expand Down Expand Up @@ -108,4 +119,5 @@ WoocommerceIntegration.propTypes = {
isInstalled: PropTypes.bool,
isPrerequisiteActive: PropTypes.bool,
activationLink: PropTypes.string.isRequired,
isSchemaAPIIntegration: PropTypes.bool,
};
2 changes: 2 additions & 0 deletions packages/js/src/settings/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
MediaPages,
PostType,
Rss,
SchemaFramework,
SiteBasics,
SiteConnections,
SiteFeatures,
Expand Down Expand Up @@ -203,6 +204,7 @@ const App = () => {
<Route path="homepage" element={ <Homepage /> } />
<Route path="format-archives" element={ <FormatArchives /> } />
<Route path="llms-txt" element={ <LlmTxt /> } />
<Route path="schema-framework" element={ <SchemaFramework /> } />
<Route path="media-pages" element={ <MediaPages /> } />
<Route path="rss" element={ <Rss /> } />
<Route path="site-basics" element={ <SiteBasics /> } />
Expand Down
1 change: 1 addition & 0 deletions packages/js/src/settings/components/advanced-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const AdvancedMenu = ( { idSuffix } ) => {

const advancedMenuItems = [
{ to: "/llms-txt", label: __( "llms.txt", "wordpress-seo" ) },
{ to: "/schema-framework", label: __( "Schema", "wordpress-seo" ) },
{ to: "/crawl-optimization", label: __( "Crawl optimization", "wordpress-seo" ) },
{ to: "/breadcrumbs", label: __( "Breadcrumbs", "wordpress-seo" ) },
{ to: "/author-archives", label: __( "Author archives", "wordpress-seo" ) },
Expand Down
7 changes: 7 additions & 0 deletions packages/js/src/settings/helpers/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ export const createSearchIndex = ( postTypes, taxonomies, { userLocale } = {} )
__( "Checklist", "wordpress-seo" ),
],
},
enable_schema: {
route: "/site-features",
routeLabel: __( "Site features", "wordpress-seo" ),
fieldId: "card-wpseo-enable_schema",
fieldLabel: __( "Schema Framework", "wordpress-seo" ),
keywords: [],
},
enable_headless_rest_endpoints: {
route: "/site-features",
routeLabel: __( "Site features", "wordpress-seo" ),
Expand Down
1 change: 1 addition & 0 deletions packages/js/src/settings/initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ domReady( () => {
[ LINK_PARAMS_NAME ]: get( window, "wpseoScriptData.linkParams", {} ),
currentPromotions: { promotions: get( window, "wpseoScriptData.currentPromotions", [] ) },
llmsTxt: get( window, "wpseoScriptData.llmsTxt", {} ),
schemaFramework: get( window, "wpseoScriptData.schemaFrameworkConfiguration", {} ),
},
} );

Expand Down
1 change: 1 addition & 0 deletions packages/js/src/settings/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as Homepage } from "./homepage";
export { default as LlmTxt } from "./llms-txt";
export { default as MediaPages } from "./media-pages";
export { default as Rss } from "./rss";
export { default as SchemaFramework } from "./schema-framework";
export { default as SiteBasics } from "./site-basics";
export { default as SiteFeatures } from "./site-features";
export { default as SiteRepresentation } from "./site-representation";
Expand Down
89 changes: 89 additions & 0 deletions packages/js/src/settings/routes/schema-framework.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useMemo } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { Alert, Code, ToggleField } from "@yoast/ui-library";
import { safeCreateInterpolateElement } from "../../helpers/i18n";
import { useFormikContext } from "formik";
import { useSelectSettings } from "../hooks";
import { FormikValueChangeField } from "../../shared-admin/components/form";
import {
FormLayout,
RouteLayout,
} from "../components";

/**
* @returns {JSX.Element} The schema framework feature route.
*/
const SchemaFramework = () => {
const seeMoreLink = useSelectSettings( "selectLink", [], "https://yoa.st/structured-data-learn-more" );
const learnMoreFilterLink = useSelectSettings( "selectLink", [], "https://yoa.st/schema-framework-filters" );
const isSchemaDisabledProgrammatically = useSelectSettings( "selectSchemaIsSchemaDisabled", [] );

const { values } = useFormikContext();

const { enable_schema: enabledSchemaFramework } = values.wpseo;

const featureDescription = sprintf(
/* translators: %1$s is replaced by "Yoast SEO". */
__( "The %1$s Schema Framework automatically builds a single, connected Schema graph for your site.", "wordpress-seo" ),
"Yoast SEO"
);

const toggleDescription = useMemo( () => safeCreateInterpolateElement(
sprintf(
/* translators: %1$s and %2$s are replaced by opening and closing <a> tags. */
__( "Add %1$sstructured data%2$s to your pages, helping search engines and LLMs understand your content and display it in rich results.", "wordpress-seo" ),
"<a>",
"</a>"
), {
// eslint-disable-next-line jsx-a11y/anchor-has-content
a: <a id="structured-data-link" href={ seeMoreLink } target="_blank" rel="noopener noreferrer" />,
}
), [ seeMoreLink ] );

const disabledSchemaAlert = useMemo( () => safeCreateInterpolateElement(
sprintf(
/* translators: %1$s expands to `wpseo_json_ld_output`, %2$s expands to `false, %3$s and %4$s are replaced by opening and closing <a> tags */
__( "It looks like the Yoast Schema Framework is disabled. The %1$s filter has been set to %2$s or an empty array, which turns off Schema output. %3$sLearn more about the filter%4$s.", "wordpress-seo" ),
"<code1 />",
"<code2 />",
"<a>",
"</a>"
), {
// eslint-disable-next-line jsx-a11y/anchor-has-content
a: <a id="llms-filter-learn-more-link" href={ learnMoreFilterLink } />,
code1: <Code>wpseo_json_ld_output</Code>,
code2: <Code>false</Code>,
}
), [ learnMoreFilterLink ] );

return (
<RouteLayout
title={ __( "Schema Framework", "wordpress-seo" ) }
description={ featureDescription }
>
<FormLayout>
<div className="yst-max-w-5xl">
<fieldset className="yst-min-width-0 yst-space-y-8">
{ ( isSchemaDisabledProgrammatically ) && <Alert id="disabled-schema-alert" variant="info" className="yst-max-w-xl">
<span className="yst-block yst-font-medium yst-mb-2">{ __( "Schema output disabled", "wordpress-seo" ) }</span>
{ disabledSchemaAlert }
</Alert> }

<div className="yst-relative yst-max-w-sm">
<FormikValueChangeField
as={ ToggleField }
type="checkbox"
name="wpseo.enable_schema"
id="input-wpseo.enable_schema"
label={ __( "Enable Schema Framework", "wordpress-seo" ) }
description={ toggleDescription }
/>
</div>
</fieldset>
</div>
</FormLayout>
</RouteLayout>
);
};

export default SchemaFramework;
10 changes: 10 additions & 0 deletions packages/js/src/settings/routes/site-features.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,16 @@ const SiteFeatures = () => {
<Title as="h2" size="2">{ __( "APIs", "wordpress-seo" ) }</Title>
</div>
<div className={ gridClassNames }>
<FeatureCard
name="wpseo.enable_schema"
cardId="card-wpseo-enable_schema"
inputId="input-wpseo-enable_schema"
imageSrc="/images/icon-schema.svg"
title={ __( "Schema Framework", "wordpress-seo" ) }
>
<p>{ __( "Outputs a single graph the web can understand. Makes every person, product, organization, and piece of content consistently readable to search engines and language models.", "wordpress-seo" ) }</p>
<LearnMoreLink id="link-schema-framework" link="https://yoa.st/site-features-schema-framework" ariaLabel={ __( "Schema Framework", "wordpress-seo" ) } />
</FeatureCard>
<FeatureCard
name="wpseo.enable_headless_rest_endpoints"
cardId="card-wpseo-enable_headless_rest_endpoints"
Expand Down
10 changes: 10 additions & 0 deletions packages/js/src/settings/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ import llmsTxt, {
LLMS_TXT_NAME,
llmsTxtSelectors,
} from "./llms-txt";
import schemaFramework, {
createInitialSchemaFrameworkState,
schemaFrameworkActions,
SCHEMA_FRAMEWORK_NAME,
schemaFrameworkSelectors,
} from "./schema-framework";
import media, { createInitialMediaState, mediaActions, mediaControls, mediaSelectors } from "./media";
import pageReducer, { getPageInitialState, PAGE_NAME, pageActions, pageControls, pageSelectors } from "./pages";
import postTypes, { createInitialPostTypesState, postTypeControls, postTypesActions, postTypesSelectors } from "./post-types";
Expand Down Expand Up @@ -69,6 +75,7 @@ const createStore = ( { initialState } ) => {
...indexablePagesActions,
...linkParamsActions,
...llmsTxtActions,
...schemaFrameworkActions,
...mediaActions,
...notificationsActions,
...pageActions,
Expand All @@ -89,6 +96,7 @@ const createStore = ( { initialState } ) => {
...indexablePagesSelectors,
...linkParamsSelectors,
...llmsTxtSelectors,
...schemaFrameworkSelectors,
...mediaSelectors,
...notificationsSelectors,
...pageSelectors,
Expand Down Expand Up @@ -116,6 +124,7 @@ const createStore = ( { initialState } ) => {
preferences: createInitialPreferencesState(),
replacementVariables: createInitialReplacementVariablesState(),
schema: createInitialSchemaState(),
[ SCHEMA_FRAMEWORK_NAME ]: createInitialSchemaFrameworkState(),
search: createInitialSearchState(),
taxonomies: createInitialTaxonomiesState(),
users: createInitialUsersState(),
Expand All @@ -137,6 +146,7 @@ const createStore = ( { initialState } ) => {
preferences,
replacementVariables,
schema,
schemaFramework,
search,
taxonomies,
users,
Expand Down
Loading
Loading