diff --git a/client/lib/url/support.js b/client/lib/url/support.js
index 2ffab16d9caf7..722ba6a0f9405 100644
--- a/client/lib/url/support.js
+++ b/client/lib/url/support.js
@@ -5,6 +5,7 @@ export const ADDING_TITAN_TO_YOUR_SITE = `${ root }/add-email/adding-professiona
export const AUTO_RENEWAL = `${ root }/manage-purchases/#automatic-renewal`;
export const CHANGE_NAME_SERVERS = `${ root }/domains/change-name-servers/`;
export const CHANGE_NAME_SERVERS_FINDING_OUT_NEW_NS = `${ root }/domains/change-name-servers/#find-your-new-name-servers`;
+export const CLEAR_CACHE = `${ root }/clear-your-sites-cache/`;
export const CONCIERGE_SUPPORT = `${ root }/concierge-support/`;
export const CONTACT = `${ root }/contact/`;
export const CALYPSO_CONTACT = '/help/contact';
diff --git a/client/my-sites/hosting/cache-card/index.js b/client/my-sites/hosting/cache-card/index.js
new file mode 100644
index 0000000000000..4f05cbd1adbb6
--- /dev/null
+++ b/client/my-sites/hosting/cache-card/index.js
@@ -0,0 +1,80 @@
+import { Button, Card } from '@automattic/components';
+import { localizeUrl } from '@automattic/i18n-utils';
+import { localize } from 'i18n-calypso';
+import { connect } from 'react-redux';
+import CardHeading from 'calypso/components/card-heading';
+import ExternalLink from 'calypso/components/external-link';
+import MaterialIcon from 'calypso/components/material-icon';
+import { CLEAR_CACHE } from 'calypso/lib/url/support';
+import { clearWordPressCache } from 'calypso/state/hosting/actions';
+import getRequest from 'calypso/state/selectors/get-request';
+import { shouldRateLimitAtomicCacheClear } from 'calypso/state/selectors/should-rate-limit-atomic-cache-clear';
+import { getSelectedSiteId } from 'calypso/state/ui/selectors';
+
+import './style.scss';
+
+const CacheCard = ( {
+ disabled,
+ shouldRateLimitCacheClear,
+ clearAtomicWordPressCache,
+ isClearingCache,
+ siteId,
+ translate,
+} ) => {
+ const clearCache = () => {
+ clearAtomicWordPressCache( siteId, 'Manually clearing again.' );
+ };
+
+ const getClearCacheContent = () => {
+ return (
+
+
+ { translate(
+ 'Be careful, clearing the cache may make your site unresponsive while it is being rebuilt. {{a}}Learn more about clearing your site’s cache{{/a}}',
+ {
+ components: {
+ a: ,
+ },
+ }
+ ) }
+
+
+ { translate( 'Clear cache' ) }
+
+ { shouldRateLimitCacheClear && (
+
+ { translate( 'You cleared the cache recently. Please wait a minute and try again.' ) }
+
+ ) }
+
+ );
+ };
+ //autorenew
+ return (
+
+
+ { translate( 'Cache' ) }
+ { getClearCacheContent() }
+
+ );
+};
+
+export default connect(
+ ( state ) => {
+ const siteId = getSelectedSiteId( state );
+
+ return {
+ shouldRateLimitCacheClear: shouldRateLimitAtomicCacheClear( state, siteId ),
+ isClearingCache: getRequest( state, clearWordPressCache( siteId ) )?.isLoading ?? false,
+ siteId,
+ };
+ },
+ {
+ clearAtomicWordPressCache: clearWordPressCache,
+ }
+)( localize( CacheCard ) );
diff --git a/client/my-sites/hosting/miscellaneous-card/style.scss b/client/my-sites/hosting/cache-card/style.scss
similarity index 100%
rename from client/my-sites/hosting/miscellaneous-card/style.scss
rename to client/my-sites/hosting/cache-card/style.scss
diff --git a/client/my-sites/hosting/main.js b/client/my-sites/hosting/main.js
index c9ec62d407ec3..7581338db6d87 100644
--- a/client/my-sites/hosting/main.js
+++ b/client/my-sites/hosting/main.js
@@ -31,8 +31,8 @@ import siteHasFeature from 'calypso/state/selectors/site-has-feature';
import { requestSite } from 'calypso/state/sites/actions';
import { isSiteOnECommerceTrial } from 'calypso/state/sites/plans/selectors';
import { getSelectedSiteId, getSelectedSiteSlug } from 'calypso/state/ui/selectors';
+import CacheCard from './cache-card';
import { HostingUpsellNudge } from './hosting-upsell-nudge';
-import MiscellaneousCard from './miscellaneous-card';
import PhpMyAdminCard from './phpmyadmin-card';
import RestorePlanSoftwareCard from './restore-plan-software-card';
import SFTPCard from './sftp-card';
@@ -184,7 +184,7 @@ class Hosting extends Component {
{ isGitHubEnabled && }
-
+
diff --git a/client/my-sites/hosting/miscellaneous-card/index.js b/client/my-sites/hosting/miscellaneous-card/index.js
deleted file mode 100644
index be54fce7f4adc..0000000000000
--- a/client/my-sites/hosting/miscellaneous-card/index.js
+++ /dev/null
@@ -1,141 +0,0 @@
-import { Button, Card, Dialog } from '@automattic/components';
-import { localize } from 'i18n-calypso';
-import { useState } from 'react';
-import { connect } from 'react-redux';
-import CardHeading from 'calypso/components/card-heading';
-import FormLabel from 'calypso/components/forms/form-label';
-import FormTextInput from 'calypso/components/forms/form-text-input';
-import MaterialIcon from 'calypso/components/material-icon';
-import { clearWordPressCache } from 'calypso/state/hosting/actions';
-import getRequest from 'calypso/state/selectors/get-request';
-import { isAtomicClearCacheEnabled } from 'calypso/state/selectors/is-atomic-clear-cache-enabled';
-import { shouldProvideReasonToClearAtomicCache } from 'calypso/state/selectors/should-provide-reason-to-clear-atomic-cache';
-import { getSelectedSiteId } from 'calypso/state/ui/selectors';
-
-import './style.scss';
-
-const MiscellaneousCard = ( {
- disabled,
- shouldProvideReasonToClearCache,
- clearAtomicWordPressCache,
- isClearCacheEnabled,
- isClearingCache,
- siteId,
- translate,
-} ) => {
- const [ showDialog, setShowDialog ] = useState( false );
- const [ reason, setReason ] = useState( '' );
-
- const clearCache = () => {
- clearAtomicWordPressCache(
- siteId,
- shouldProvideReasonToClearCache ? reason : 'Clearing again in less than 24 hours.'
- );
- setShowDialog( false );
- setReason( '' );
- };
-
- const showConfirmationDialog = () => {
- setShowDialog( true );
- };
-
- const closeConfirmationDialog = () => {
- setShowDialog( false );
- };
-
- const onReasonChange = ( event ) => {
- setReason( event.target.value );
- };
-
- const getClearCacheContent = () => {
- const clearCacheText = translate( 'Clear Cache' );
- const clearCacheDisabled = ! reason || reason.length < 3;
- const deleteButtons = [
- { translate( 'Cancel' ) } ,
-
- { clearCacheText }
- ,
- ];
-
- return (
-
-
- { translate( '{{strong}}Warning!{{/strong}}', {
- components: {
- strong: ,
- },
- } ) }
-
-
- { translate(
- 'Clearing the cache on your site may make it unresponsive while the cache is rebuilding. ' +
- 'Please use this feature responsibly.'
- ) }
-
-
- { clearCacheText }
-
-
-
- { clearCacheText }
-
- { translate( "Please let us know why you are clearing your site's cache." ) }
-
- { translate(
- 'We use this information to audit plugins and give valuable feedback to plugin developers. ' +
- 'It is our way of giving back to the community and helping people learn more about WordPress.'
- ) }
-
-
-
-
-
-
- );
- };
-
- if ( ! isClearCacheEnabled ) {
- return null;
- }
-
- return (
-
-
- { translate( 'Miscellaneous' ) }
- { getClearCacheContent() }
-
- );
-};
-
-export default connect(
- ( state ) => {
- const siteId = getSelectedSiteId( state );
-
- return {
- shouldProvideReasonToClearCache: shouldProvideReasonToClearAtomicCache( state, siteId ),
- isClearCacheEnabled: isAtomicClearCacheEnabled( state, siteId ),
- isClearingCache: getRequest( state, clearWordPressCache( siteId ) )?.isLoading ?? false,
- siteId,
- };
- },
- {
- clearAtomicWordPressCache: clearWordPressCache,
- }
-)( localize( MiscellaneousCard ) );
diff --git a/client/state/selectors/is-atomic-clear-cache-enabled.js b/client/state/selectors/is-atomic-clear-cache-enabled.js
deleted file mode 100644
index 2f2fd2fb866aa..0000000000000
--- a/client/state/selectors/is-atomic-clear-cache-enabled.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { currentUserHasFlag } from 'calypso/state/current-user/selectors';
-import { isSupportSession } from 'calypso/state/support/selectors';
-
-export function isAtomicClearCacheEnabled( state ) {
- return currentUserHasFlag( state, 'calypso_atomic_clear_cache' ) || isSupportSession( state );
-}
diff --git a/client/state/selectors/should-provide-reason-to-clear-atomic-cache.js b/client/state/selectors/should-provide-reason-to-clear-atomic-cache.js
deleted file mode 100644
index 2a9ebfced3f6b..0000000000000
--- a/client/state/selectors/should-provide-reason-to-clear-atomic-cache.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import 'calypso/state/hosting/init';
-
-const ONE_DAY_IN_MILLISECONDS = 86400 * 1000;
-
-export function shouldProvideReasonToClearAtomicCache( state, siteId ) {
- const lastCacheCleared = state.atomicHosting?.[ siteId ]?.lastCacheClearTimestamp;
-
- if ( ! lastCacheCleared ) {
- return true;
- }
-
- const oneDayAgo = new Date().valueOf() - ONE_DAY_IN_MILLISECONDS;
- const wasCleanedMoreThanOneDayAgo = oneDayAgo > lastCacheCleared;
-
- return wasCleanedMoreThanOneDayAgo;
-}
diff --git a/client/state/selectors/should-rate-limit-atomic-cache-clear.js b/client/state/selectors/should-rate-limit-atomic-cache-clear.js
new file mode 100644
index 0000000000000..315cf6e4e5ace
--- /dev/null
+++ b/client/state/selectors/should-rate-limit-atomic-cache-clear.js
@@ -0,0 +1,14 @@
+import 'calypso/state/hosting/init';
+
+const ONE_MINUTE_IN_MILLISECONDS = 60 * 1000;
+
+export function shouldRateLimitAtomicCacheClear( state, siteId ) {
+ const lastCacheCleared = state.atomicHosting?.[ siteId ]?.lastCacheClearTimestamp;
+
+ if ( ! lastCacheCleared ) {
+ return false;
+ }
+
+ const rateLimitTime = new Date().valueOf() - ONE_MINUTE_IN_MILLISECONDS;
+ return lastCacheCleared > rateLimitTime;
+}
diff --git a/client/state/selectors/test/should-provide-reason-to-clear-atomic-cache.js b/client/state/selectors/test/should-provide-reason-to-clear-atomic-cache.js
deleted file mode 100644
index b92bbab7706af..0000000000000
--- a/client/state/selectors/test/should-provide-reason-to-clear-atomic-cache.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import { shouldProvideReasonToClearAtomicCache } from 'calypso/state/selectors/should-provide-reason-to-clear-atomic-cache';
-
-const ONE_DAY_IN_MILLISECONDS = 86400 * 1000;
-const ONE_SECOND = 1000;
-const SITE_ID = 123;
-const TIMESTAMP = 1234567890;
-
-const generateState = ( { timestamp } ) => ( {
- atomicHosting: {
- [ SITE_ID ]: {
- lastCacheClearTimestamp: timestamp,
- },
- },
-} );
-
-describe( 'shouldProvideReasonToClearAtomicCache', () => {
- beforeAll( () => {
- jest.useFakeTimers( 'modern' ).setSystemTime( TIMESTAMP );
- } );
-
- afterAll( () => {
- jest.useRealTimers();
- } );
-
- test( 'should return true if there is no stored timestamp', () => {
- expect(
- shouldProvideReasonToClearAtomicCache( generateState( { timestamp: null } ), SITE_ID )
- ).toBe( true );
- } );
-
- test( 'should return true if the cache was cleared more than 24 hours ago', () => {
- expect(
- shouldProvideReasonToClearAtomicCache(
- generateState( { timestamp: TIMESTAMP - ONE_DAY_IN_MILLISECONDS - ONE_SECOND } ),
- SITE_ID
- )
- ).toBe( true );
- } );
-
- test( 'should return false if the cache was cleared less than 24 hours ago', () => {
- expect(
- shouldProvideReasonToClearAtomicCache(
- generateState( { timestamp: TIMESTAMP - ONE_DAY_IN_MILLISECONDS } ),
- SITE_ID
- )
- ).toBe( false );
- } );
-} );
diff --git a/client/state/selectors/test/should-rate-limit-atomic-cache-clear.js b/client/state/selectors/test/should-rate-limit-atomic-cache-clear.js
new file mode 100644
index 0000000000000..f97bef716363f
--- /dev/null
+++ b/client/state/selectors/test/should-rate-limit-atomic-cache-clear.js
@@ -0,0 +1,48 @@
+import { shouldRateLimitAtomicCacheClear } from 'calypso/state/selectors/should-rate-limit-atomic-cache-clear';
+
+const ONE_MINUTE_IN_MILLISECONDS = 60 * 1000;
+const ONE_SECOND = 1000;
+const SITE_ID = 123;
+const TIMESTAMP = 1234567890;
+
+const generateState = ( { timestamp } ) => ( {
+ atomicHosting: {
+ [ SITE_ID ]: {
+ lastCacheClearTimestamp: timestamp,
+ },
+ },
+} );
+
+describe( 'shouldRateLimitAtomicCacheClear', () => {
+ beforeAll( () => {
+ jest.useFakeTimers( 'modern' ).setSystemTime( TIMESTAMP );
+ } );
+
+ afterAll( () => {
+ jest.useRealTimers();
+ } );
+
+ test( 'should return false if there is no stored timestamp', () => {
+ expect( shouldRateLimitAtomicCacheClear( generateState( { timestamp: null } ), SITE_ID ) ).toBe(
+ false
+ );
+ } );
+
+ test( 'should return false if the cache was cleared more than a minute ago', () => {
+ expect(
+ shouldRateLimitAtomicCacheClear(
+ generateState( { timestamp: TIMESTAMP - ONE_MINUTE_IN_MILLISECONDS - ONE_SECOND } ),
+ SITE_ID
+ )
+ ).toBe( false );
+ } );
+
+ test( 'should return true if the cache was cleared less than a minute ago', () => {
+ expect(
+ shouldRateLimitAtomicCacheClear(
+ generateState( { timestamp: TIMESTAMP - ONE_MINUTE_IN_MILLISECONDS + ONE_SECOND } ),
+ SITE_ID
+ )
+ ).toBe( true );
+ } );
+} );