diff --git a/includes/AdminBarSiteStatusBadge.php b/includes/AdminBarSiteStatusBadge.php new file mode 100644 index 0000000..76cc98e --- /dev/null +++ b/includes/AdminBarSiteStatusBadge.php @@ -0,0 +1,150 @@ +container = $container; + + $this->defaults = array( + 'admin_bar_cs_active' => __( 'Coming soon', 'newfold-module-coming-soon' ), + 'admin_bar_cs_inactive' => __( 'Live', 'newfold-module-coming-soon' ), + ); + + add_action( 'admin_bar_menu', array( $this, 'site_status_badge' ), 31 ); + add_action( 'wp_head', array( $this, 'site_status_badge_styles' ) ); + add_action( 'admin_head', array( $this, 'site_status_badge_styles' ) ); + add_action( 'update_option_nfd_coming_soon', array( __CLASS__, 'site_status_badge_timer' ), 10, 2 ); + } + + /** + * Add site status badge to WP admin bar. + * + * @param WP_Admin_Bar $admin_bar An instance of the WP_Admin_Bar class. + */ + public function site_status_badge( WP_Admin_Bar $admin_bar ): void { + if ( current_user_can( 'manage_options' ) ) { + + $is_coming_soon = isComingSoonActive(); + $title = $is_coming_soon ? $this->defaults['admin_bar_cs_active'] : $this->defaults['admin_bar_cs_inactive']; + $class = $this->site_status_badge_class( $is_coming_soon ); + + $site_status_menu = array( + 'id' => 'nfd-site-visibility-badge', + 'parent' => 'root-default', + 'href' => admin_url( 'admin.php?page=' . $this->container->plugin()->id . '&nfd-target=coming-soon-section#/settings' ), + 'title' => $title, + 'meta' => array( + 'class' => 'nfd-site-status-badge-' . $class, + ), + ); + $admin_bar->add_menu( $site_status_menu ); + } + } + + /** + * Determine the class for the site status badge. + * + * @param bool $is_coming_soon Whether the site is in Coming Soon mode. + */ + private function site_status_badge_class( $is_coming_soon ): string { + $class = $is_coming_soon ? 'coming-soon' : 'live'; + + // Hide badge if the site has been live for more than 10 minutes. + if ( ! $is_coming_soon && ! get_transient( 'nfd_coming_soon_site_status_badge_timer' ) ) { + $class = 'hidden'; + } + + return $class; + } + + /** + * Output CSS for site status badge. + */ + public function site_status_badge_styles(): void { + if ( is_admin_bar_showing() ) { + ?> + + container()->plugin()->id, 'admin_app_url' => \admin_url( 'admin.php?page=newfold' ), 'admin_notice_text' => __( 'Your site has Coming Soon mode active.', 'newfold-module-coming-soon' ), - 'admin_bar_text' => '
' . __( 'Coming Soon Active', 'newfold-module-coming-soon' ) . '
', - 'admin_bar_label' => __( 'Site Status: ', 'newfold-module-coming-soon' ), - 'admin_bar_cs_active' => __( 'Not Live', 'newfold-module-coming-soon' ), - 'admin_bar_cs_inactive' => __( 'Live', 'newfold-module-coming-soon' ), 'template_page_title' => __( 'Coming Soon!', 'newfold-module-coming-soon' ), 'template_styles' => false, 'template_content' => false, @@ -49,6 +45,9 @@ public function __construct( Container $container ) { // add plugin version to plugin styles file for cache busting $this->args['template_styles'] = $this->args['template_styles'] . '?v=' . container()->plugin()->version; } + + new WooCommerceOptionsSync(); + // set up all actions \add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) ); \add_action( 'rest_api_init', array( $this, 'rest_api_init' ) ); @@ -58,15 +57,13 @@ public function __construct( Container $container ) { \add_action( 'wp_ajax_newfold_coming_soon_subscribe', array( $this, 'coming_soon_subscribe' ) ); \add_action( 'wp_ajax_nopriv_newfold_coming_soon_subscribe', array( $this, 'coming_soon_subscribe' ) ); \add_action( 'plugins_loaded', array( $this, 'coming_soon_prevent_emails' ) ); - \add_action( 'admin_bar_menu', array( $this, 'newfold_site_status' ), 100 ); - \add_action( 'wp_body_open', array( $this, 'site_preview_warning' ) ); - \add_action( 'admin_head', array( $this, 'admin_bar_coming_soon_admin_styles' ) ); - \add_action( 'wp_head', array( $this, 'admin_bar_coming_soon_admin_styles' ) ); \add_filter( 'default_option_nfd_coming_soon', array( $this, 'filter_coming_soon_fallback' ) ); \add_action( 'update_option_nfd_coming_soon', array( $this, 'on_update_nfd_coming_soon' ), 10, 2 ); \add_action( 'update_option_mm_coming_soon', array( $this, 'on_update_mm_coming_soon' ), 10, 2 ); \add_filter( 'jetpack_is_under_construction_plugin', array( $this, 'filter_jetpack_is_under_construction' ) ); + new AdminBarSiteStatusBadge( $container ); + new SitePreviewWarning(); new PrePublishModal(); } @@ -245,99 +242,6 @@ public function notice_display() { } } - /** - * Some basic styles to control visibility of the coming soon state in the admin bar - */ - public function admin_bar_coming_soon_admin_styles() { - if( is_user_logged_in() ) { - ?> - - '; - $content .= $this->args['admin_bar_label']; - $content .= ''; - $content .= $this->args['admin_bar_cs_active']; - $content .= ''; - $content .= ''; - $content .= $this->args['admin_bar_cs_inactive']; - $content .= ''; - $content .= ''; - - $site_status_menu = array( - 'id' => 'site-status', - 'parent' => 'top-secondary', - 'href' => admin_url( 'admin.php?page=' . $this->container->plugin()->id . '&nfd-target=coming-soon-section#/settings' ), - 'title' => $content, - ); - $admin_bar->add_menu( $site_status_menu ); - } - } - - /** - * Load warning on site Preview - */ - public function site_preview_warning() { - if ( isComingSoonActive() ) { - echo "
" . esc_html__( 'Site Preview - This site is NOT LIVE, only admins can see this view.', 'newfold-module-coming-soon' ) . "
"; - } - } - /** * Load the coming soon page, if necessary. */ diff --git a/includes/SitePreviewWarning.php b/includes/SitePreviewWarning.php new file mode 100644 index 0000000..fb21086 --- /dev/null +++ b/includes/SitePreviewWarning.php @@ -0,0 +1,29 @@ +" . esc_html__( 'Site Preview - This site is NOT LIVE, only admins can see this view.', 'newfold-module-coming-soon' ) . ""; + } +} diff --git a/includes/WooCommerceOptionsSync.php b/includes/WooCommerceOptionsSync.php new file mode 100644 index 0000000..322c349 --- /dev/null +++ b/includes/WooCommerceOptionsSync.php @@ -0,0 +1,152 @@ +disable(); + } else { + $nfd_coming_soon_service->enable(); + } + } + + // Sync the coming soon options when the woocommerce_coming_soon option is updated. + if ( 'woocommerce_coming_soon' === $option_name ) { + if ( $value ) { + $nfd_coming_soon_service->enable(); + } else { + $nfd_coming_soon_service->disable(); + } + } + } + + /** + * Sync the coming soon options when the woocommerce_coming_soon option is newly added. + */ + public static function sync_when_woocommerce_option_is_added(): void { + $nfd_coming_soon_service = self::get_service(); + $new_value = $nfd_coming_soon_service->is_enabled(); + + self::sync_woocommerce_coming_soon_option( $new_value ); + } + + /** + * Sync options when WooCommerce is initialized but the 'woocommerce_coming_soon' option is not set. + */ + public static function sync_when_woocommerce_option_is_missing(): void { + if ( optionExists( 'woocommerce_coming_soon' ) ) { + return; + } + + self::sync_when_woocommerce_option_is_added(); + } +} diff --git a/includes/functions.php b/includes/functions.php index 3fec9b3..f41e1ee 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -4,9 +4,24 @@ /** * Check if the coming soon module is active. - * - * @return bool */ -function isComingSoonActive() { +function isComingSoonActive(): bool { return ( new Service() )->is_enabled(); -} \ No newline at end of file +} + +/** + * Check if WooCommerce is activated + */ +function isWoocommerceActive(): bool { + return class_exists( 'woocommerce' ); +} + +/** + * Check if an option exists + * + * @param string $option_name The option name + */ +function optionExists( $option_name ): bool { + $value = get_option( $option_name, 'not_set' ); + return 'not_set' !== $value; +} diff --git a/static/js/coming-soon.js b/static/js/coming-soon.js index f192671..9f43d2d 100644 --- a/static/js/coming-soon.js +++ b/static/js/coming-soon.js @@ -107,16 +107,93 @@ return value; }; + /** + * Toggle the site status badge in the admin bar. + * + * @param {boolean} newState The new state of the site status. + */ const toggleAdminBarSiteStatus = ( newState ) => { - const siteStatus = document.querySelector( - '#wp-toolbar #nfd-site-status' + /** + * The badge elements for NFD and WooCommerce. + * Only one of them will be active at a time. + * When WooCommerce is active, the WooCommerce badge will be used. + * When WooCommerce is not active, the NFD badge will be used. + */ + const badge = { + nfd: { + selector: '#wp-toolbar #wp-admin-bar-nfd-site-visibility-badge', + comingSoon: { + text: 'Coming soon', + class: 'nfd-site-status-badge-coming-soon', + }, + live: { + text: 'Live', + class: 'nfd-site-status-badge-live', + }, + hidden: { + class: 'nfd-site-status-badge-hidden', + }, + }, + woocommerce: { + selector: + '#wp-toolbar #wp-admin-bar-woocommerce-site-visibility-badge', + comingSoon: { + text: 'Coming soon', + class: 'woocommerce-site-status-badge-coming-soon', + }, + live: { + text: 'Live', + class: 'woocommerce-site-status-badge-live', + }, + hidden: { + class: 'woocommerce-site-status-badge-hidden', + }, + }, + }; + + const getActiveBadge = () => { + // Return the WooCommerce badge if WooCommerce is active. + if ( window.NewfoldRuntime.isWoocommerceActive ) { + return badge.woocommerce; + } + return badge.nfd; + }; + const activeBadge = getActiveBadge(); + + const siteVisibilityBadge = document.querySelector( + activeBadge.selector ); - if ( ! siteStatus ) { + if ( ! siteVisibilityBadge ) { return; } - siteStatus.setAttribute( 'data-coming-soon', newState ); + const toggle = ( newState ) => { + if ( newState ) { + // Coming soon + siteVisibilityBadge.classList.remove( + activeBadge.live.class, + activeBadge.hidden.class + ); + siteVisibilityBadge.classList.add( activeBadge.comingSoon.class ); + const textElement = siteVisibilityBadge.querySelector( 'a.ab-item' ); + if ( textElement ) { + textElement.textContent = activeBadge.comingSoon.text; + } + } else { + // Live + siteVisibilityBadge.classList.remove( + activeBadge.comingSoon.class, + activeBadge.hidden.class + ); + siteVisibilityBadge.classList.add( activeBadge.live.class ); + const textElement = siteVisibilityBadge.querySelector( 'a.ab-item' ); + if ( textElement ) { + textElement.textContent = activeBadge.live.text; + } + } + }; + toggle( newState ); }; window.addEventListener( 'DOMContentLoaded', () => { diff --git a/tests/cypress/integration/coming-soon-woo.cy.js b/tests/cypress/integration/coming-soon-woo.cy.js new file mode 100644 index 0000000..84e2e45 --- /dev/null +++ b/tests/cypress/integration/coming-soon-woo.cy.js @@ -0,0 +1,67 @@ +// + +describe( 'Coming Soon with WooCommerce', function () { + before( () => { + // Set coming soon option to true to start with + cy.exec( `npx wp-env run cli wp option update mm_coming_soon true` ); + cy.exec( `npx wp-env run cli wp option update nfd_coming_soon true` ); + + // Activate WooCommerce + cy.exec( `npx wp-env run cli wp plugin install woocommerce --activate`, { + timeout: 40000, + log: true, + } ); + } ); + + after( () => { + // Deactivate WooCommerce + cy.exec( `npx wp-env run cli wp plugin deactivate woocommerce`, { + timeout: 40000, + } ); + } ); + + it( 'Replace our admin bar site status badge with WooCommerce\'s when active', () => { + // Visit settings page + cy.visit( + '/wp-admin/admin.php?page=' + + Cypress.env( 'pluginId' ) + + '#/settings' + ); + + // Our badge shouldn't be visible + cy.get( '#wp-toolbar #wp-admin-bar-nfd-site-visibility-badge' ) + .should( 'not.exist' ); + + // WooCommerce badge should be visible + cy.get( '#wp-toolbar #wp-admin-bar-woocommerce-site-visibility-badge a.ab-item' ) + .contains( 'a', 'Coming soon' ) + .should( 'be.visible' ); + }); + + it ( 'Our plugin settings should toggle WooCommerce admin bar badge', () => { + // Deactivate coming soon - Launch Site + cy.get( '[data-id="coming-soon-toggle"]' ).click(); + cy.wait( 1000 ); + + // WooCommerce badge should now be live + cy.get( '#wp-toolbar .woocommerce-site-status-badge-live a.ab-item' ) + .contains( 'a', 'Live' ) + .should( 'be.visible' ); + + // Re-enable coming soon mode + cy.get( '[data-id="coming-soon-toggle"]' ) + .click(); + cy.wait( 1000 ); + + // WooCommerce badge should now be coming soon + cy.get( '#wp-toolbar .woocommerce-site-status-badge-coming-soon a.ab-item' ) + .contains( 'a', 'Coming soon' ) + .should( 'be.visible' ); + }); + + it( 'Hide our site preview notice when WooCommerce is active', () => { + cy.visit( '/' ); + cy.get( '.nfd-site-preview-warning' ) + .should( 'not.exist' ); + }); +} ); diff --git a/tests/cypress/integration/coming-soon.cy.js b/tests/cypress/integration/coming-soon.cy.js index cc3a7ae..150127b 100644 --- a/tests/cypress/integration/coming-soon.cy.js +++ b/tests/cypress/integration/coming-soon.cy.js @@ -6,7 +6,12 @@ describe( 'Coming Soon', function () { before( () => { // Set coming soon option to true to start with cy.exec( `npx wp-env run cli wp option update mm_coming_soon true` ); - cy.exec( `npx wp-env run cli wp option update nfd_coming_soon true` ); + cy.exec( `npx wp-env run cli wp option update nfd_coming_soon true` ); + + // Deactivate WooCommerce + cy.exec( `npx wp-env run cli wp plugin deactivate woocommerce`, { + timeout: 40000, + } ); } ); it( 'Coming Soon is active', () => { @@ -18,7 +23,7 @@ describe( 'Coming Soon', function () { cy.reload(); // Initial Coming Soon State - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-coming-soon' ) + cy.get( '#wp-toolbar #wp-admin-bar-nfd-site-visibility-badge' ) .scrollIntoView() .should( 'be.visible' ); @@ -39,15 +44,9 @@ describe( 'Coming Soon', function () { it( 'Displays Coming Soon in Site Status Admin Toolbar', () => { // Admin bar contains label - cy.get( '#wp-toolbar #wp-admin-bar-site-status' ) - .contains( 'div', 'Site Status' ) - .should( 'be.visible' ); - // Admin bar contains status - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-coming-soon' ) - .scrollIntoView() + cy.get( '#wp-toolbar #wp-admin-bar-nfd-site-visibility-badge a.ab-item' ) + .contains( 'a', 'Coming soon' ) .should( 'be.visible' ); - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-live' ) - .should( 'not.be.visible' ); } ); it( 'Has Coming Soon Section on Home', () => { @@ -73,7 +72,7 @@ describe( 'Coming Soon', function () { } ); it( 'Coming Soon Admin bar links to setting', () => { - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-coming-soon' ).click(); + cy.get( '#wp-toolbar #wp-admin-bar-nfd-site-visibility-badge a.ab-item' ).click(); cy.location().should( ( loc ) => { expect( loc.hash ).to.eq( '#/settings' ) }); @@ -87,7 +86,7 @@ describe( 'Coming Soon', function () { ); // Deactivate coming soon - Launch Site cy.get( '[data-id="coming-soon-toggle"]' ).click(); - cy.wait( 500 ); + cy.wait( 2000 ); // Toggle is false cy.get( '[data-id="coming-soon-toggle"]' ) @@ -95,8 +94,9 @@ describe( 'Coming Soon', function () { .and( 'include', 'false' ); // Admin bar is updated - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-live' ) + cy.get( '#wp-toolbar .nfd-site-status-badge-live a.ab-item' ) .scrollIntoView() + .contains( 'a', 'Live' ) .should( 'be.visible' ); // Snackbar notice displays properly @@ -114,7 +114,7 @@ describe( 'Coming Soon', function () { // Activate Coming Soon - Unlaunch Site cy.get( '[data-id="coming-soon-toggle"]' ).click(); - cy.wait( 500 ); + cy.wait( 2000 ); // Toggle is true cy.get( '[data-id="coming-soon-toggle"]' ) @@ -122,8 +122,9 @@ describe( 'Coming Soon', function () { .and( 'include', 'true' ); // Admin bar is updated - cy.get( '#wp-toolbar #wp-admin-bar-site-status #nfd-site-status-coming-soon' ) + cy.get( '#wp-toolbar .nfd-site-status-badge-coming-soon a.ab-item' ) .scrollIntoView() + .contains( 'a', 'Coming soon' ) .should( 'be.visible' ); // Snackbar notice displays properly @@ -139,6 +140,13 @@ describe( 'Coming Soon', function () { .should( 'be.visible' ); } ); + it( 'Displays Coming Soon Site Preview Warning', () => { + cy.visit( '/' ); + cy.get( '.nfd-site-preview-warning' ) + .contains( 'div', 'Site Preview' ) + .should( 'be.visible' ); + } ); + it( 'Displays Coming Soon on Frontend', () => { cy.logout(); cy.visit( '/' );