diff --git a/packages/js/images/yoast-connect-google-site-kit.svg b/packages/js/images/yoast-connect-google-site-kit.svg new file mode 100644 index 00000000000..ad3bfb2f879 --- /dev/null +++ b/packages/js/images/yoast-connect-google-site-kit.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/js/src/dashboard/components/dashboard.js b/packages/js/src/dashboard/components/dashboard.js index 62f58e02edc..a1b1935a457 100644 --- a/packages/js/src/dashboard/components/dashboard.js +++ b/packages/js/src/dashboard/components/dashboard.js @@ -1,5 +1,10 @@ import { Scores } from "../scores/components/scores"; import { PageTitle } from "./page-title"; +import { SiteKitSetupWidget } from "./site-kit-setup-widget"; +import { get } from "lodash"; +import { useCallback } from "@wordpress/element"; +import { useToggleState } from "@yoast/ui-library"; +import { useSelect } from "@wordpress/data"; /** * @type {import("../index").ContentType} ContentType @@ -15,12 +20,39 @@ import { PageTitle } from "./page-title"; * @param {Endpoints} endpoints The endpoints. * @param {Object} headers The headers for the score requests. * @param {Links} links The links. + * * @returns {JSX.Element} The element. */ +// The complexity is cause by the google site kit feature flag which is temporary. +// eslint-disable-next-line complexity export const Dashboard = ( { contentTypes, userName, features, endpoints, headers, links } ) => { + const siteKitConfiguration = get( window, "wpseoScriptData.dashboard.siteKitConfiguration", { + isInstalled: false, + isActive: false, + isSetupCompleted: false, + isConnected: false, + installUrl: "", + activateUrl: "", + setupUrl: "", + isFeatureEnabled: false, + } ); + const [ showGoogleSiteKit, , , , setRemoveGoogleSiteKit ] = useToggleState( true ); + const learnMorelink = useSelect( select => select( "@yoast/general" ).selectLink( "https://yoa.st/google-site-kit-learn-more" ), [] ); + const handleRemovePermanently = useCallback( ()=>{ + /* eslint-disable-next-line */ + // TODO: Implement the remove permanently functionality. + setRemoveGoogleSiteKit(); + }, [ setRemoveGoogleSiteKit ] ); + return ( <> + { showGoogleSiteKit && siteKitConfiguration.isFeatureEnabled && }
{ features.indexables && features.seoAnalysis && ( diff --git a/packages/js/src/dashboard/components/site-kit-setup-widget.js b/packages/js/src/dashboard/components/site-kit-setup-widget.js new file mode 100644 index 00000000000..8452807de78 --- /dev/null +++ b/packages/js/src/dashboard/components/site-kit-setup-widget.js @@ -0,0 +1,139 @@ +import { Button, Paper, Stepper, Title, DropdownMenu } from "@yoast/ui-library"; +import { ReactComponent as YoastConnectSiteKit } from "../../../images/yoast-connect-google-site-kit.svg"; +import { __ } from "@wordpress/i18n"; +import { CheckCircleIcon } from "@heroicons/react/solid"; +import { ArrowRightIcon, XIcon, TrashIcon } from "@heroicons/react/outline"; + +const steps = [ + __( "INSTALL", "wordpress-seo" ), + __( "ACTIVATE", "wordpress-seo" ), + __( "SET UP", "wordpress-seo" ), + __( "CONNECT", "wordpress-seo" ), +]; + +/** + * The google site kit connection guide widget. + * + * @param {boolean} isInstalled Whether the plugin is installed. + * @param {boolean} isActive Whether the feature is active. + * @param {boolean} isSetupCompleted Whether the setup is complete. + * @param {boolean} isConnected Whether the connection is active. + * @param {string} installUrl The URL to install Site Kit. + * @param {string} activateUrl The URL to activate Site Kit. + * @param {string} setupUrl The URL to setup Site Kit. + * @param {function} onRemove The function to call when the widget is removed. + * @param {function} onRemovePermanently The function to call when the widget is removed permanently. + * @param {string} learnMorelink The URL to learn more about the feature. + * + * @returns {JSX.Element} The widget. + */ +export const SiteKitSetupWidget = ( { + installUrl, + activateUrl, + setupUrl, + isConnected, + isActive, + isSetupCompleted, + isInstalled, + onRemove, + onRemovePermanently, + learnMorelink, +} ) => { + const stepsStatuses = [ isInstalled, isActive, isSetupCompleted, isConnected ]; + + let currentStep = stepsStatuses.findIndex( status => ! status ); + const overAllCompleted = currentStep === -1; + + if ( currentStep === -1 ) { + currentStep = steps.length - 1; + } + + const buttonProps = [ + { + children: __( "Install Site Kit by Google", "wordpress-seo" ), + href: installUrl, + as: "a", + }, + { + children: __( "Activate Site Kit by Google", "wordpress-seo" ), + href: activateUrl, + as: "a", + }, + { + children: __( "Set up Site Kit by Google", "wordpress-seo" ), + href: setupUrl, + as: "a", + }, + { + children: __( "Connect Site Kit by Google", "wordpress-seo" ), + }, + ]; + + return + + + + + + { __( "Remove until next visit", "wordpress-seo" ) } + + + + { __( "Remove permanently", "wordpress-seo" ) } + + + + +
+ + { steps.map( ( label, index ) => ( + { label } + ) ) } + +
+ { __( "Expand your dashboard with insights from Google!", "wordpress-seo" ) } +

{ __( "Bring together powerful tools like Google Analytics and Search Console for a complete overview of your website's performance, all in one seamless dashboard.", "wordpress-seo" ) }

+ + { __( "What you'll get:", "wordpress-seo" ) } +
    +
  • + + { __( "Actionable insights into traffic, SEO, and user behavior to grow your audience.", "wordpress-seo" ) } +
  • +
  • + + { __( "Key performance metrics to fine-tune your website and optimize like a pro.", "wordpress-seo" ) } +
  • +
+
+ + { overAllCompleted + ? <> + + + + : <> + + + } +
+
; +}; + + diff --git a/packages/js/src/integrations-page/recommended-integrations.js b/packages/js/src/integrations-page/recommended-integrations.js index fa8ddd68b43..f2794f1962e 100644 --- a/packages/js/src/integrations-page/recommended-integrations.js +++ b/packages/js/src/integrations-page/recommended-integrations.js @@ -81,14 +81,14 @@ const RecommendedIntegrations = [ const siteKitProps = { isInstalled: get( window, "wpseoIntegrationsData.site_kit_configuration.isInstalled", false ), isActive: get( window, "wpseoIntegrationsData.site_kit_configuration.isActive", false ), - afterSetup: get( window, "wpseoIntegrationsData.site_kit_configuration.setup_completed", false ), + isSetupCompleted: get( window, "wpseoIntegrationsData.site_kit_configuration.isSetupCompleted", false ), isConnected: get( window, "wpseoIntegrationsData.site_kit_configuration.isConnected", false ), - installUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.install_url", "" ), - activateUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.activate_url", "" ), - setupUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.setup_url", "" ), + installUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.installUrl", "" ), + activateUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.activateUrl", "" ), + setupUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.setupUrl", "" ), }; -const isSiteKitFeatureEnabled = get( window, "wpseoIntegrationsData.site_kit_configuration.feature_enabled", false ); +const isSiteKitFeatureEnabled = get( window, "wpseoIntegrationsData.site_kit_configuration.isFeatureEnabled", false ); if ( isSiteKitFeatureEnabled ) { RecommendedIntegrations.push( ); } diff --git a/packages/js/src/integrations-page/site-kit-integration.js b/packages/js/src/integrations-page/site-kit-integration.js index c62ef14313d..a7a53891bdd 100644 --- a/packages/js/src/integrations-page/site-kit-integration.js +++ b/packages/js/src/integrations-page/site-kit-integration.js @@ -1,6 +1,6 @@ import { __, sprintf } from "@wordpress/i18n"; import { CheckIcon } from "@heroicons/react/solid"; -import { createInterpolateElement, useCallback } from "@wordpress/element"; +import { createInterpolateElement } from "@wordpress/element"; import PropTypes from "prop-types"; import { SimpleIntegration } from "./simple-integration"; import { ReactComponent as SiteKitLogo } from "../../images/site-kit-logo.svg"; @@ -49,7 +49,7 @@ const SuccessfullyConnected = () => { * The Site Kit integration component. * * @param {boolean} isActive Whether the integration is active. - * @param {boolean} afterSetup Whether the integration has been set up. + * @param {boolean} isSetupCompleted Whether the integration has been set up. * @param {boolean} isInstalled Whether the integration is installed. * @param {boolean} isConnected Whether the integration is connected. * @param {string} installUrl The installation url. @@ -58,50 +58,39 @@ const SuccessfullyConnected = () => { * * @returns {WPElement} The Site Kit integration component. */ -export const SiteKitIntegration = ( { isActive, afterSetup, isInstalled, isConnected, installUrl, activateUrl, setupUrl } ) => { +export const SiteKitIntegration = ( { isActive, isSetupCompleted, isInstalled, isConnected, installUrl, activateUrl, setupUrl } ) => { const [ isModalOpen, toggleModal ] = useToggleState( false ); const [ isDisconnectModalOpen, toggleDisconnectModal ] = useToggleState( false ); + const stepsStatuses = [ isInstalled, isActive, isSetupCompleted, isConnected ]; + let currentStep = stepsStatuses.findIndex( status => ! status ); + const successfullyConnected = currentStep === -1; - const getButtonProps = useCallback( () => { - if ( ! isInstalled ) { - return { - children: __( "Install Site Kit by Google", "wordpress-seo" ), - as: "a", - href: installUrl, - }; - } - if ( ! isActive ) { - return { - children: __( "Activate Site Kit by Google", "wordpress-seo" ), - as: "a", - href: activateUrl, - }; - } - if ( ! afterSetup ) { - return { - children: __( "Set up Site Kit by Google", "wordpress-seo" ), - as: "a", - href: setupUrl, - }; - } - if ( ! isConnected ) { - return { - children: __( "Connect Site Kit by Google", "wordpress-seo" ), - as: "button", - onClick: toggleModal, - }; - } - - return { - children: __( "Disconnect", "wordpress-seo" ), - as: "button", - variant: "secondary", - onClick: toggleDisconnectModal, - }; - }, [ isInstalled, isActive, afterSetup, isConnected, installUrl, activateUrl, toggleModal ] ); + if ( currentStep === -1 ) { + currentStep = stepsStatuses.length - 1; + } + const buttonProps = [ + { + children: __( "Install Site Kit by Google", "wordpress-seo" ), + href: installUrl, + as: "a", + }, + { + children: __( "Activate Site Kit by Google", "wordpress-seo" ), + href: activateUrl, + as: "a", + }, + { + children: __( "Set up Site Kit by Google", "wordpress-seo" ), + href: setupUrl, + as: "a", + }, + { + children: __( "Connect Site Kit by Google", "wordpress-seo" ), + onClick: toggleModal, + }, + ]; - const successfullyConnected = isInstalled && isActive && afterSetup && isConnected; return ( <> - { successfullyConnected && } - + : + ) } + + ); +}; + +ButtonItem.propTypes = { + children: PropTypes.node.isRequired, + className: PropTypes.string, +}; + +/** + * Dropdown menu icon trigger. + * + * @param {string} [className] CSS class. + * @param {string} [screenReaderTriggerLabel] Screen reader label for the menu trigger. + * @param {JSX.node} [Icon] Icon component. + * + * @returns {JSX.Element} Menu trigger component. + */ +const IconTrigger = ( { className, screenReaderTriggerLabel, Icon = DotsVerticalIcon, ...props } ) => ( + + { ( { open } ) => <> + + { screenReaderTriggerLabel } + } + +); + +IconTrigger.propTypes = { + className: PropTypes.string, + screenReaderTriggerLabel: PropTypes.string.isRequired, + Icon: PropTypes.node, +}; + +/** + * Dropdown menu list. + * + * @param {JSX.node} children Content of the menu. + * @param {string} [className] CSS class. + * + * @returns {JSX.Element} Menu list component. + */ +const List = ( { children, className, ...props } ) => { + return ( + + + { children } + + + ); +}; + +List.propTypes = { + children: PropTypes.node.isRequired, + className: PropTypes.string, +}; + +/** + * + * @param {JSX.node} children Content of the menu. + * @param {object} props The menu props. + * + * @returns {JSX.Element} Dropdown menu component. + */ +export const DropdownMenu = ( { children, ...props } ) => { + return ( + + { children } + + ); +}; + +DropdownMenu.propTypes = { + children: PropTypes.node.isRequired, +}; + +DropdownMenu.Item = Menu.Item; +DropdownMenu.Item.displayName = "DropdownMenu.Item"; + +DropdownMenu.ButtonItem = ButtonItem; +DropdownMenu.ButtonItem.displayName = "DropdownMenu.ButtonItem"; + +DropdownMenu.IconTrigger = IconTrigger; +DropdownMenu.IconTrigger.displayName = "DropdownMenu.IconTrigger"; + +DropdownMenu.Trigger = Menu.Button; +DropdownMenu.Trigger.displayName = "DropdownMenu.Trigger"; + +DropdownMenu.List = List; +DropdownMenu.List.displayName = "DropdownMenu.List"; + +DropdownMenu.displayName = "DropdownMenu"; diff --git a/packages/ui-library/src/components/dropdown-menu/stories.js b/packages/ui-library/src/components/dropdown-menu/stories.js new file mode 100644 index 00000000000..a240e092898 --- /dev/null +++ b/packages/ui-library/src/components/dropdown-menu/stories.js @@ -0,0 +1,51 @@ +import { DropdownMenu } from "."; +import React from "react"; +import { XIcon, TrashIcon } from "@heroicons/react/outline"; +import { component } from "./docs"; + +export const Factory = { + render: () => + + + + { ( { active } ) => ( +
Item
+ ) } +
+ + { ( { active } ) => ( +
Item
+ ) } +
+ + + Button Item + + + + Button Item + +
+
, +}; + + +export default { + title: "2) Components/DropdownMenu", + component: DropdownMenu, + argTypes: { + children: { control: "text" }, + }, + parameters: { + docs: { + description: { component }, + }, + }, + decorators: [ + ( Story ) => ( +
+ +
+ ), + ], +}; diff --git a/packages/ui-library/src/components/dropdown-menu/style.css b/packages/ui-library/src/components/dropdown-menu/style.css new file mode 100644 index 00000000000..40d540dfb60 --- /dev/null +++ b/packages/ui-library/src/components/dropdown-menu/style.css @@ -0,0 +1,36 @@ +@layer components { + .yst-root { + .yst-dropdown-menu__icon-trigger { + @apply + yst-text-slate-400 + yst-rounded-full + focus:yst-text-slate-600 + focus:yst-outline + focus:yst-outline-2 + focus:yst-outline-offset-2 + focus:yst-outline-primary-500; + } + + .yst-dropdown-menu__item--button { + @apply + yst-items-center + yst-w-full + yst-ring-0 + yst-rounded-none + focus:yst-outline-none + focus:yst-bg-slate-100 + hover:yst-bg-slate-100 + yst-outline-none; + } + + .yst-dropdown-menu__list { + @apply + yst-rounded-md + yst-border + yst-border-slate-200 + yst-shadow-sm + yst-bg-white + focus-visible:yst-outline-none; + } + } +} \ No newline at end of file diff --git a/packages/ui-library/src/components/stepper/docs/component.md b/packages/ui-library/src/components/stepper/docs/component.md new file mode 100644 index 00000000000..3abcddd17fc --- /dev/null +++ b/packages/ui-library/src/components/stepper/docs/component.md @@ -0,0 +1 @@ +The stepper element takes takes the number of steps and current step and has Step component to render each step. \ No newline at end of file diff --git a/packages/ui-library/src/components/stepper/docs/index.js b/packages/ui-library/src/components/stepper/docs/index.js new file mode 100644 index 00000000000..a01392a1542 --- /dev/null +++ b/packages/ui-library/src/components/stepper/docs/index.js @@ -0,0 +1 @@ +export { default as component } from "./component.md"; diff --git a/packages/ui-library/src/components/stepper/index.js b/packages/ui-library/src/components/stepper/index.js new file mode 100644 index 00000000000..d0175e9f200 --- /dev/null +++ b/packages/ui-library/src/components/stepper/index.js @@ -0,0 +1,115 @@ +import classNames from "classnames"; +import PropTypes from "prop-types"; +import React, { forwardRef, useRef, useState, useCallback, createContext, useContext, useLayoutEffect } from "react"; +import { CheckIcon } from "@heroicons/react/solid"; +import { ProgressBar } from "../../index"; +import { noop } from "lodash"; + +/** + * Context for the stepper. Used to add a reference to the step. + */ +const StepperContext = createContext( { + addStepRef: noop, +} ); + +/** + * Step component. + * + * @param {JSX.Node} children The step label or children. + * @param {boolean} isComplete Is the step complete. + * @param {boolean} isActive Is the step + * + * @returns {JSX.Element} The step element. + */ +const Step = ( { children, isComplete, isActive } ) => { + const { addStepRef } = useContext( StepperContext ); + return ( +
+
+ { isComplete && } + +
+
+
{ children }
+
+ ); +}; + +Step.displayName = "Step"; +Step.propTypes = { + children: PropTypes.node.isRequired, + isActive: PropTypes.bool.isRequired, + isComplete: PropTypes.bool.isRequired, +}; + +/** + * + * @param {JSX.Node} children Content of the stepper. + * @param {number} [currentStep] The current step, starts from 0. + * @param {string} [className] Optional extra className. + * + * @returns {JSX.Element} The Stepper element. + */ +export const Stepper = forwardRef( ( { children, currentStep, className = "" }, ref ) => { + const [ progressBarPosition, setProgressBarPosition ] = useState( { + left: 0, + right: 0, + } ); + const stepRef = useRef( [] ); + + useLayoutEffect( () => { + if ( stepRef.current.length > 0 ) { + const firstStepRect = stepRef.current[ 0 ].getBoundingClientRect(); + const lastStepRect = stepRef.current[ stepRef.current.length - 1 ].getBoundingClientRect(); + setProgressBarPosition( { + left: firstStepRect.width / 2, + right: lastStepRect.width / 2, + } ); + } + }, [ stepRef.current ] ); + + const addStepRef = useCallback( ( el ) => ( stepRef.current.push( el ) ), [ stepRef.current ] ); + + return ( + +
+ + { children } + + +
+
+ ); +} ); + +Stepper.displayName = "Stepper"; +Stepper.propTypes = { + currentStep: PropTypes.number.isRequired, + children: PropTypes.node.isRequired, + className: PropTypes.string, +}; +Stepper.defaultProps = { + className: "", +}; + +Stepper.Step = Step; +Stepper.Context = StepperContext; +Stepper.Step.displayName = "Stepper.Step"; + diff --git a/packages/ui-library/src/components/stepper/stories.js b/packages/ui-library/src/components/stepper/stories.js new file mode 100644 index 00000000000..1fd0cede4b2 --- /dev/null +++ b/packages/ui-library/src/components/stepper/stories.js @@ -0,0 +1,65 @@ +import React, { useState, useCallback } from "react"; +import { useArgs } from "@storybook/preview-api"; +import { Stepper } from "."; +import { component } from "./docs"; +import { Button } from "../../index"; + +export const Factory = { + parameters: { + controls: { disable: false }, + }, + render: ( args ) =>{ + const [ isComplete, setIsComplete ] = useState( false ); + const steps = [ "INSTALL", "ACTIVATE", "SET UP", "CONNECT" ]; + const [ { className, currentStep }, updateArgs ] = useArgs(); + + const handleNext = useCallback( () => { + if ( currentStep < steps.length - 1 ) { + setIsComplete( false ); + updateArgs( { currentStep: currentStep + 1 } ); + } else if ( currentStep === steps.length - 1 && ! isComplete ) { + setIsComplete( true ); + } else if ( isComplete ) { + setIsComplete( false ); + updateArgs( { currentStep: 0 } ); + } + }, [ setIsComplete, updateArgs, isComplete, currentStep ] ); + + return <> + + { steps.map( ( step, index ) => index || isComplete } + isActive={ currentStep === index } + > + { step } + ) } + + + + + ; + }, +}; + +export default { + title: "2) Components/Stepper", + component: Stepper, + argTypes: { + className: { control: "text" }, + currentStep: { control: "number" }, + }, + parameters: { + docs: { + description: { component }, + }, + }, + args: { + className: "yst-mb-5", + currentStep: 0, + }, +}; diff --git a/packages/ui-library/src/components/stepper/style.css b/packages/ui-library/src/components/stepper/style.css new file mode 100644 index 00000000000..139e0a3eea8 --- /dev/null +++ b/packages/ui-library/src/components/stepper/style.css @@ -0,0 +1,57 @@ +@layer components { + .yst-root { + + .yst-stepper { + @apply yst-relative yst-flex yst-justify-between yst-items-center; + + .yst-progress-bar__progress { + @apply yst-duration-500; + } + + } + + .yst-step { + @apply yst-flex yst-flex-col yst-items-center; + } + + .yst-step__circle { + @apply yst-bg-white + yst-ring-slate-300 + yst-w-6 + yst-h-6 + yst-ring-2 + yst-rounded-full + yst-z-10 + yst-relative; + } + + .yst-step__icon { + @apply yst-absolute yst-top-1/2 yst-left-1/2 yst-transform -yst-translate-x-1/2 -yst-translate-y-1/2; + } + + .yst-step--active { + @apply yst-text-primary-500; + + .yst-step__circle { + @apply + yst-bg-white + yst-text-white + yst-ring-primary-500 + yst-transition-all + yst-ease-in + yst-delay-500; + } + + .yst-step__icon{ + @apply yst-transition-all yst-ease-in; + } + } + + .yst-step--complete { + @apply yst-text-slate-900; + .yst-step__circle { + @apply yst-bg-primary-500 yst-text-white yst-ring-primary-500 yst-transition-none yst-delay-0; + } + } + } +} diff --git a/packages/ui-library/src/index.js b/packages/ui-library/src/index.js index 830ac850945..1c4c9c962a8 100644 --- a/packages/ui-library/src/index.js +++ b/packages/ui-library/src/index.js @@ -41,6 +41,8 @@ export { default as TextField } from "./components/text-field"; export { default as TextareaField } from "./components/textarea-field"; export { default as ToggleField } from "./components/toggle-field"; export { TooltipContainer, TooltipTrigger, TooltipWithContext, useTooltipContext } from "./components/tooltip-container"; +export { DropdownMenu } from "./components/dropdown-menu"; +export { Stepper } from "./components/stepper"; export * from "./hooks"; export * from "./constants"; diff --git a/src/dashboard/application/configuration/dashboard-configuration.php b/src/dashboard/application/configuration/dashboard-configuration.php index eae738da4a0..9ad97d3c2e0 100644 --- a/src/dashboard/application/configuration/dashboard-configuration.php +++ b/src/dashboard/application/configuration/dashboard-configuration.php @@ -4,13 +4,16 @@ // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong namespace Yoast\WP\SEO\Dashboard\Application\Configuration; +use Yoast\WP\SEO\Conditionals\Google_Site_Kit_Feature_Conditional; use Yoast\WP\SEO\Dashboard\Application\Content_Types\Content_Types_Repository; use Yoast\WP\SEO\Dashboard\Application\Endpoints\Endpoints_Repository; +use Yoast\WP\SEO\Dashboard\Infrastructure\Integrations\Site_Kit; use Yoast\WP\SEO\Dashboard\Infrastructure\Nonces\Nonce_Repository; use Yoast\WP\SEO\Editors\Application\Analysis_Features\Enabled_Analysis_Features_Repository; use Yoast\WP\SEO\Editors\Framework\Keyphrase_Analysis; use Yoast\WP\SEO\Editors\Framework\Readability_Analysis; use Yoast\WP\SEO\Helpers\Indexable_Helper; +use Yoast\WP\SEO\Helpers\Options_Helper; use Yoast\WP\SEO\Helpers\User_Helper; /** @@ -60,6 +63,27 @@ class Dashboard_Configuration { */ private $nonce_repository; + /** + * The Google Site Kit conditional. + * + * @var Google_Site_Kit_Feature_Conditional + */ + private $google_site_kit_conditional; + + /** + * The options helper. + * + * @var Options_Helper + */ + private $options_helper; + + /** + * The site kit integration configuration data. + * + * @var Site_Kit + */ + private $site_kit_integration_data; + /** * The constructor. * @@ -67,10 +91,13 @@ class Dashboard_Configuration { * @param Indexable_Helper $indexable_helper The indexable helper * repository. * @param User_Helper $user_helper The user helper. - * @param Enabled_Analysis_Features_Repository $enabled_analysis_features_repository The analysis feature - * repository. + * @param Enabled_Analysis_Features_Repository $enabled_analysis_features_repository The analysis feature. + * repository. * @param Endpoints_Repository $endpoints_repository The endpoints repository. * @param Nonce_Repository $nonce_repository The nonce repository. + * @param Google_Site_Kit_Feature_Conditional $google_site_kit_conditional The Google Site Kit conditional. + * @param Options_Helper $options_helper The options helper. + * @param Site_Kit $site_kit_integration_data The site kit integration configuration data. */ public function __construct( Content_Types_Repository $content_types_repository, @@ -78,7 +105,10 @@ public function __construct( User_Helper $user_helper, Enabled_Analysis_Features_Repository $enabled_analysis_features_repository, Endpoints_Repository $endpoints_repository, - Nonce_Repository $nonce_repository + Nonce_Repository $nonce_repository, + Google_Site_Kit_Feature_Conditional $google_site_kit_conditional, + Options_Helper $options_helper, + Site_Kit $site_kit_integration_data ) { $this->content_types_repository = $content_types_repository; $this->indexable_helper = $indexable_helper; @@ -86,6 +116,9 @@ public function __construct( $this->enabled_analysis_features_repository = $enabled_analysis_features_repository; $this->endpoints_repository = $endpoints_repository; $this->nonce_repository = $nonce_repository; + $this->google_site_kit_conditional = $google_site_kit_conditional; + $this->options_helper = $options_helper; + $this->site_kit_integration_data = $site_kit_integration_data; } /** @@ -106,6 +139,7 @@ public function get_configuration(): array { )->to_array(), 'endpoints' => $this->endpoints_repository->get_all_endpoints()->to_array(), 'nonce' => $this->nonce_repository->get_rest_nonce(), + 'siteKitConfiguration' => $this->site_kit_integration_data->to_array(), ]; } } diff --git a/src/dashboard/infrastructure/integrations/site-kit.php b/src/dashboard/infrastructure/integrations/site-kit.php index 33291a16cb7..bf7b93920a1 100644 --- a/src/dashboard/infrastructure/integrations/site-kit.php +++ b/src/dashboard/infrastructure/integrations/site-kit.php @@ -61,14 +61,14 @@ public function to_array(): array { $site_kit_setup_url = \self_admin_url( 'admin.php?page=googlesitekit-splash' ); return [ - 'isInstalled' => \file_exists( \WP_PLUGIN_DIR . '/' . self::SITE_KIT_FILE ), - 'isActive' => \is_plugin_active( self::SITE_KIT_FILE ), - 'setup_completed' => \get_option( 'googlesitekit_has_connected_admins', false ) === '1', - 'isConnected' => $this->options_helper->get( 'google_site_kit_connected', false ), - 'feature_enabled' => ( new Google_Site_Kit_Feature_Conditional() )->is_met(), - 'install_url' => $site_kit_install_url, - 'activate_url' => $site_kit_activate_url, - 'setup_url' => $site_kit_setup_url, + 'isInstalled' => \file_exists( \WP_PLUGIN_DIR . '/' . self::SITE_KIT_FILE ), + 'isActive' => \is_plugin_active( self::SITE_KIT_FILE ), + 'isSetupCompleted' => \get_option( 'googlesitekit_has_connected_admins', false ) === '1', + 'isConnected' => $this->options_helper->get( 'google_site_kit_connected', false ), + 'isFeatureEnabled' => ( new Google_Site_Kit_Feature_Conditional() )->is_met(), + 'installUrl' => $site_kit_install_url, + 'activateUrl' => $site_kit_activate_url, + 'setupUrl' => $site_kit_setup_url, ]; } diff --git a/tests/Unit/Integrations/Admin/Integrations_Page_Integration_Test.php b/tests/Unit/Integrations/Admin/Integrations_Page_Integration_Test.php index ddcfd212669..73668200bca 100644 --- a/tests/Unit/Integrations/Admin/Integrations_Page_Integration_Test.php +++ b/tests/Unit/Integrations/Admin/Integrations_Page_Integration_Test.php @@ -160,14 +160,14 @@ public function test_enqueue_assets() { $this->elementor_conditional->expects( 'is_met' )->andReturnFalse(); $this->jetpack_conditional->expects( 'is_met' )->andReturnFalse(); $site_kit_config = [ - 'isInstalled' => false, - 'isActive' => false, - 'setup_completed' => false, - 'isConnected' => false, - 'feature_enabled' => false, - 'install_url' => 'example.com', - 'activate_url' => 'example.com', - 'setup_url' => 'example.com', + 'isInstalled' => false, + 'isActive' => false, + 'isSetupCompleted' => false, + 'isConnected' => false, + 'isFeatureEnabled' => false, + 'installUrl' => 'example.com', + 'activateUrl' => 'example.com', + 'setupUrl' => 'example.com', ]; $this->site_kit_configuration->expects( 'to_array' )->andReturn( $site_kit_config );