diff --git a/.github/files/list-changed-projects.sh b/.github/files/list-changed-projects.sh
index 151d8a9dd5679..b57a0cb4826a9 100755
--- a/.github/files/list-changed-projects.sh
+++ b/.github/files/list-changed-projects.sh
@@ -32,4 +32,4 @@ else
die "Unsupported GITHUB_EVENT_NAME \"$GITHUB_EVENT_NAME\""
fi
-pnpx jetpack dependencies list "${ARGS[@]}" | jq -cR 'reduce inputs as $i ({}; .[$i] |= true)'
+pnpx jetpack dependencies list "${ARGS[@]}" | jq -ncR 'reduce inputs as $i ({}; .[$i] |= true)'
diff --git a/.github/files/setup-wordpress-env.sh b/.github/files/setup-wordpress-env.sh
index 2caa7692c58b5..d98076fd31a8d 100755
--- a/.github/files/setup-wordpress-env.sh
+++ b/.github/files/setup-wordpress-env.sh
@@ -35,12 +35,6 @@ case "$WP_BRANCH" in
;;
latest)
LATEST=$(php ./tools/get-wp-version.php)
- # 5.8.x still requires a monkey-patched obsolete version of phpunit.
- # If that's latest, run the coverage test with the upcoming 5.9 instead.
- # @todo: Remove this once WordPress 5.9 is "latest".
- if [[ "$LATEST" == 5.8.* && "$TEST_SCRIPT" == "test-coverage" ]]; then
- LATEST=master
- fi
git clone --depth=1 --branch "$LATEST" git://develop.git.wordpress.org/ /tmp/wordpress-latest
;;
previous)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4bb161252f06a..04e6af9c41d4b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -163,7 +163,7 @@ importers:
'@automattic/jetpack-analytics': workspace:^0.1.7
'@automattic/jetpack-api': workspace:^0.8.3
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-config': workspace:^0.1.3
'@babel/core': 7.16.0
'@babel/preset-react': 7.16.0
@@ -276,7 +276,7 @@ importers:
'@automattic/jetpack-analytics': workspace:^0.1.7
'@automattic/jetpack-api': workspace:^0.8.3
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@babel/core': 7.16.0
'@babel/preset-react': 7.16.0
'@wordpress/base-styles': 4.0.4
@@ -318,7 +318,7 @@ importers:
specifiers:
'@automattic/jetpack-api': workspace:^0.8.3
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@babel/core': 7.16.0
'@babel/preset-react': 7.16.0
'@wordpress/components': 19.1.6
@@ -349,7 +349,7 @@ importers:
projects/js-packages/partner-coupon:
specifiers:
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-connection': workspace:^0.15.0-alpha
'@babel/core': 7.16.0
'@babel/preset-react': 7.16.0
@@ -584,7 +584,7 @@ importers:
projects/packages/identity-crisis:
specifiers:
- '@automattic/jetpack-idc': workspace:^0.9.0
+ '@automattic/jetpack-idc': workspace:^0.9.1-alpha
'@automattic/jetpack-webpack-config': workspace:^1.1.1
'@babel/core': 7.16.0
'@babel/preset-env': 7.16.4
@@ -647,7 +647,7 @@ importers:
specifiers:
'@automattic/jetpack-analytics': workspace:^0.1.7
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-connection': workspace:^0.15.0-alpha
'@automattic/jetpack-webpack-config': workspace:^1.1.1
'@babel/core': 7.16.0
@@ -660,6 +660,7 @@ importers:
'@testing-library/react': 11.2.7
'@testing-library/react-hooks': 4.0.1
'@testing-library/user-event': 12.8.3
+ '@wordpress/api-fetch': 6.0.0
'@wordpress/components': 19.1.6
'@wordpress/data': 6.1.5
'@wordpress/i18n': 4.2.4
@@ -679,6 +680,7 @@ importers:
'@automattic/jetpack-analytics': link:../../js-packages/analytics
'@automattic/jetpack-components': link:../../js-packages/components
'@automattic/jetpack-connection': link:../../js-packages/connection
+ '@wordpress/api-fetch': 6.0.0
'@wordpress/components': 19.1.6_aae888dfa296766acacf1a733aa50b3a
'@wordpress/data': 6.1.5_react@17.0.2
'@wordpress/i18n': 4.2.4
@@ -714,7 +716,7 @@ importers:
'@automattic/color-studio': 2.5.0
'@automattic/jetpack-analytics': workspace:^0.1.7
'@automattic/jetpack-api': workspace:^0.8.3
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-webpack-config': workspace:^1.1.1
'@babel/core': 7.16.0
'@babel/plugin-proposal-nullish-coalescing-operator': 7.16.0
@@ -811,7 +813,7 @@ importers:
specifiers:
'@automattic/jetpack-api': workspace:^0.8.3
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-connection': workspace:^0.15.0-alpha
'@automattic/jetpack-webpack-config': workspace:^1.1.1
'@babel/core': 7.16.0
@@ -934,9 +936,9 @@ importers:
'@automattic/jetpack-analytics': workspace:^0.1.7
'@automattic/jetpack-api': workspace:^0.8.3
'@automattic/jetpack-base-styles': workspace:^0.1.7
- '@automattic/jetpack-components': workspace:^0.10.3
+ '@automattic/jetpack-components': workspace:^0.10.4-alpha
'@automattic/jetpack-connection': workspace:^0.15.0-alpha
- '@automattic/jetpack-licensing': workspace:^0.4.4
+ '@automattic/jetpack-licensing': workspace:^0.4.5-alpha
'@automattic/jetpack-partner-coupon': workspace:^0.1.7-alpha
'@automattic/jetpack-webpack-config': workspace:^1.1.1
'@automattic/popup-monitor': 1.0.0
@@ -7112,6 +7114,15 @@ packages:
'@wordpress/i18n': 4.2.4
'@wordpress/url': 3.3.1
+ /@wordpress/api-fetch/6.0.0:
+ resolution: {integrity: sha512-pSfqdzaOO7/SrIDkFJDhVDs0DLy1WmrtIxz4rTub+H538MolyHmUh9xs1aIyakgC9PH7DrkzVmj00d8QXBcVcw==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@babel/runtime': 7.16.7
+ '@wordpress/i18n': 4.3.0
+ '@wordpress/url': 3.4.0
+ dev: false
+
/@wordpress/autop/3.2.3:
resolution: {integrity: sha512-o66vC+aZPmJGMie+Emqa5gtfQYKbLXqGCESTfingXyMxXEpCa4qOEOi1D6vwX61sf3+k2qJ4bvKwJ5nZXjDaSQ==}
engines: {node: '>=12'}
@@ -8458,6 +8469,13 @@ packages:
dependencies:
'@babel/runtime': 7.16.7
+ /@wordpress/hooks/3.3.0:
+ resolution: {integrity: sha512-RSOZS5cr9h830VHE7XQ/NbgIfQQXtuSWrb2mX+4uN4qK6ua2hUfZS/twW4af2H2beistK/rUDPpUVO9x7XSQ5w==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@babel/runtime': 7.16.7
+ dev: false
+
/@wordpress/html-entities/3.2.3:
resolution: {integrity: sha512-406VUz8CuKgKGrW/wjRB877soSqGhGDwK4sSuNoIC1FvpfniZ0ijpqfsdhJOOynWdz+RYN1wAsfogBpzuREJOg==}
engines: {node: '>=12'}
@@ -8490,6 +8508,20 @@ packages:
sprintf-js: 1.1.2
tannin: 1.2.0
+ /@wordpress/i18n/4.3.0:
+ resolution: {integrity: sha512-VN0fPhhphX1EkVcCMxirLkwVhvdLNDTg5uYfLeK/e3OSUrKhlFFiI+JyfOXZOrD7LLRz6c6wzCPrCw3ehjmkrg==}
+ engines: {node: '>=12'}
+ hasBin: true
+ dependencies:
+ '@babel/runtime': 7.16.7
+ '@wordpress/hooks': 3.3.0
+ gettext-parser: 1.4.0
+ lodash: 4.17.21
+ memize: 1.1.0
+ sprintf-js: 1.1.2
+ tannin: 1.2.0
+ dev: false
+
/@wordpress/icons/2.10.3:
resolution: {integrity: sha512-hVXArGOHLE5pL1G3rHNzsUEuTR4/G6lB+enKYwhYSSIqWuSbyXbZq3nvibxpepPrLy9B3d5t6aR6QUmjMVzIcQ==}
dependencies:
@@ -8994,6 +9026,14 @@ packages:
'@babel/runtime': 7.16.7
lodash: 4.17.21
+ /@wordpress/url/3.4.0:
+ resolution: {integrity: sha512-E4jnotQrNwvrl6Zdo3S3bDBOzVKnTH7xnOr03VuNtjvWtu2ANRS9R/cD9yVXbvDdiBC2jAJHmCrEMVCxGJmuIw==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@babel/runtime': 7.16.7
+ lodash: 4.17.21
+ dev: false
+
/@wordpress/viewport/4.0.7_react@17.0.2:
resolution: {integrity: sha512-huxUrFW6JNhj/hUfvftZeht3B6HF0jk10oyHW3dPcFW57ceecJTDB9BdS7a99B1LBP8AWjdN8x/3SqrMwE4yfg==}
engines: {node: '>=12'}
@@ -19691,7 +19731,7 @@ packages:
dependencies:
array.prototype.flat: 1.2.5
global-cache: 1.2.1
- react-with-styles: 3.2.3
+ react-with-styles: 3.2.3_react-dom@17.0.2+react@17.0.2
/react-with-styles/3.2.3:
resolution: {integrity: sha512-MTI1UOvMHABRLj5M4WpODfwnveHaip6X7QUMI2x6zovinJiBXxzhA9AJP7MZNaKqg1JRFtHPXZdroUC8KcXwlQ==}
@@ -20745,7 +20785,7 @@ packages:
klona: 2.0.5
neo-async: 2.6.2
sass: 1.43.3
- webpack: 5.65.0_webpack-cli@4.9.1
+ webpack: 5.65.0
dev: true
/sass-loader/12.4.0_webpack@5.65.0:
diff --git a/projects/js-packages/components/changelog/update-my-jetpack-styles b/projects/js-packages/components/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..4e563d7a121dc
--- /dev/null
+++ b/projects/js-packages/components/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+RNA: Improve layout structure with Container and Col
diff --git a/projects/js-packages/components/components/admin-page/footer.jsx b/projects/js-packages/components/components/admin-page/footer.jsx
deleted file mode 100644
index cb130d487295f..0000000000000
--- a/projects/js-packages/components/components/admin-page/footer.jsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * External dependencies
- */
-import React from 'react';
-import { __ } from '@wordpress/i18n';
-import PropTypes from 'prop-types';
-
-/**
- * Internal dependencies
- */
-import styles from './style.module.scss';
-import JetpackFooter from '../jetpack-footer';
-import Row from '../layout/row';
-import Container from '../layout/container';
-import Col from '../layout/col';
-
-/**
- * Footer for the AdminPage component
- *
- * @param {object} props - Component properties.
- * @returns {React.Component} AdminPage component.
- */
-const AdminPageFooter = props => {
- const { moduleName, a8cLogoHref } = props;
-
- return (
-
- { showHeader &&
}
- { children }
- { showFooter &&
}
+
+ { showHeader && (
+
+
+
+
+
+ ) }
+
+ { children }
+
+ { showFooter && (
+
+
+
+
+
+ ) }
);
};
diff --git a/projects/js-packages/components/components/admin-page/style.module.scss b/projects/js-packages/components/components/admin-page/style.module.scss
index 141e917c78f0d..72aa0ab6a900e 100644
--- a/projects/js-packages/components/components/admin-page/style.module.scss
+++ b/projects/js-packages/components/components/admin-page/style.module.scss
@@ -1,10 +1,8 @@
-@import '@automattic/jetpack-base-styles/style';
-
-.jp-admin-page {
+.admin-page {
margin-left: -20px; // to neutralize the padding of #wpcontent.
-}
+ background-color: var(--jp-white);
-.jp-admin-page-section {
- padding: 40px 0px;
- background-color: white;
+ @media (max-width: 782px) {
+ margin-left: -10px; // to neutralize the padding of #wpcontent.
+ }
}
diff --git a/projects/js-packages/components/components/admin-section/basic/index.jsx b/projects/js-packages/components/components/admin-section/basic/index.jsx
index f107f45dbd9a3..03efbc2ef6dd1 100644
--- a/projects/js-packages/components/components/admin-section/basic/index.jsx
+++ b/projects/js-packages/components/components/admin-section/basic/index.jsx
@@ -7,7 +7,6 @@ import React from 'react';
* Internal dependencies
*/
import styles from './style.module.scss';
-import Container from '../../layout/container';
/**
* This is the wrapper component to build sections within your admin page.
@@ -17,11 +16,7 @@ import Container from '../../layout/container';
*/
const AdminSection = props => {
const { children } = props;
- return (
-
- { children }
-
- );
+ return
{ children }
;
};
export default AdminSection;
diff --git a/projects/js-packages/components/components/admin-section/basic/style.module.scss b/projects/js-packages/components/components/admin-section/basic/style.module.scss
index cbe5d2d6f1866..b31bf1adb230b 100644
--- a/projects/js-packages/components/components/admin-section/basic/style.module.scss
+++ b/projects/js-packages/components/components/admin-section/basic/style.module.scss
@@ -1,6 +1,3 @@
-
-.jp-admin-section {
- padding: 64px 0px;
- background-color: white;
-
+.section {
+ background-color: var(--jp-white);
}
diff --git a/projects/js-packages/components/components/admin-section/hero/index.jsx b/projects/js-packages/components/components/admin-section/hero/index.jsx
index e7c46fb5e5749..adc642f0e7123 100644
--- a/projects/js-packages/components/components/admin-section/hero/index.jsx
+++ b/projects/js-packages/components/components/admin-section/hero/index.jsx
@@ -7,7 +7,6 @@ import React from 'react';
* Internal dependencies
*/
import styles from './style.module.scss';
-import Container from '../../layout/container';
/**
* The wrapper component for a Hero Section to be used in admin pages.
@@ -17,11 +16,7 @@ import Container from '../../layout/container';
*/
const AdminSectionHero = props => {
const { children } = props;
- return (
-
- { children }
-
- );
+ return
{ children }
;
};
export default AdminSectionHero;
diff --git a/projects/js-packages/components/components/admin-section/hero/style.module.scss b/projects/js-packages/components/components/admin-section/hero/style.module.scss
index 6eb3fc404c2ee..65c3200b871a5 100644
--- a/projects/js-packages/components/components/admin-section/hero/style.module.scss
+++ b/projects/js-packages/components/components/admin-section/hero/style.module.scss
@@ -1,11 +1,3 @@
-@import '@automattic/jetpack-base-styles/style';
-
-.jp-admin-section-hero {
- padding: 48px 0px 64px 0px;
+.section-hero {
background: var( --jp-white-off );
-
- h1, h2, h3, h4, h5, h6 {
- margin-top: 0px;
- line-height: 1.2;
- }
}
diff --git a/projects/js-packages/components/components/admin-section/stories/index.jsx b/projects/js-packages/components/components/admin-section/stories/index.jsx
index a5cd28c1f377f..b0ecc05221ac9 100644
--- a/projects/js-packages/components/components/admin-section/stories/index.jsx
+++ b/projects/js-packages/components/components/admin-section/stories/index.jsx
@@ -6,7 +6,7 @@ import AdminSection from '../basic';
import AdminSectionHero from '../hero';
import AdminPage from '../../admin-page';
import Col from '../../layout/col';
-import Row from '../../layout/row';
+import Container from '../../layout/container';
export default {
title: 'Playground/Admin Sections',
@@ -16,20 +16,20 @@ export default {
const Template = () => (
-
+
Sample Hero section
This is a sample Hero section
-
+
-
+
Sample Section
This is a sample section
-
+
);
@@ -39,22 +39,22 @@ export const _default = Template.bind( {} );
export const onlyBasic = () => (
-
+
Sample Section
This is a sample section
-
+
);
export const onlyHero = () => (
-
+
Sample Hero Section
This is a sample Hero section
-
+
);
diff --git a/projects/js-packages/components/components/layout/col/index.jsx b/projects/js-packages/components/components/layout/col/index.jsx
index 07d9fccf85abb..93580d4b685c7 100644
--- a/projects/js-packages/components/components/layout/col/index.jsx
+++ b/projects/js-packages/components/components/layout/col/index.jsx
@@ -17,28 +17,29 @@ import styles from './style.module.scss';
* @returns {React.Component} Col component.
*/
const Col = props => {
- const { children, sm, md, lg } = props;
- const small = Number.isInteger( sm ) ? sm : 0;
- const medium = Number.isInteger( md ) ? md : 0;
- const large = Number.isInteger( lg ) ? lg : 0;
- const minimum = [ small, medium, large ].reduce( ( prev, curr ) =>
- curr > 0 && curr < prev ? curr : prev
- );
+ const { children, className } = props;
- const className = classnames(
- small > 0 ? styles[ 'sm-col-span-' + small ] : styles[ 'sm-col-span-' + minimum ],
- medium > 0 ? styles[ 'md-col-span-' + medium ] : styles[ 'md-col-span-' + minimum ],
- large > 0 ? styles[ 'lg-col-span-' + large ] : styles[ 'lg-col-span-' + minimum ]
- );
- return
{ children }
;
+ const sm = Math.min( 4, props.sm ?? 4 ); // max of 4, if undefined = 4
+ const md = Math.min( 8, props.md ?? 8 ); // max of 8, if undefined = 8
+ const lg = Math.min( 12, props.lg ?? 12 ); // max of 12, if undefined = 12
+
+ const colClassName = classnames( className, {
+ [ styles[ `col-sm-${ sm }` ] ]: Number.isInteger( sm ),
+ [ styles[ `col-md-${ md }` ] ]: Number.isInteger( md ),
+ [ styles[ `col-lg-${ lg }` ] ]: Number.isInteger( lg ),
+ } );
+
+ return
{ children }
;
};
Col.proptypes = {
- /** Colspan for small viewport. Needs to be an integer. Defaults to the smallest colspan informed. */
- sm: PropTypes.number,
- /** Colspan for medium viewport. Needs to be an integer. Defaults to the smallest colspan informed. */
+ /** Custom className to be inserted. */
+ className: PropTypes.string,
+ /** Colspan for small viewport. Needs to be an integer. */
+ sm: PropTypes.number.isRequired,
+ /** Colspan for medium viewport. Needs to be an integer. */
md: PropTypes.number,
- /** Colspan for large viewport. Needs to be an integer. Defaults to the smallest colspan informed. */
+ /** Colspan for large viewport. Needs to be an integer. */
lg: PropTypes.number,
};
diff --git a/projects/js-packages/components/components/layout/col/style.module.scss b/projects/js-packages/components/components/layout/col/style.module.scss
index 706ad07fc8959..558c50c0e1651 100644
--- a/projects/js-packages/components/components/layout/col/style.module.scss
+++ b/projects/js-packages/components/components/layout/col/style.module.scss
@@ -1,35 +1,20 @@
-@import '@automattic/jetpack-base-styles/style';
-
-@for $i from 1 through 4 {
- .sm-col-span-#{$i} {
- grid-column-end: span #{$i};
- }
-}
-
-@include for-phone-up {
- @for $i from 1 through 8 {
- .md-col-span-#{$i} {
+@mixin cols($size, $columns) {
+ @for $i from 1 through $columns {
+ .col-#{$size}-#{$i} {
grid-column-end: span #{$i};
}
}
}
-@include for-tablet-up {
- @for $i from 1 through 12 {
- .lg-col-span-#{$i} {
- grid-column-end: span #{$i};
- }
- }
+@media ( min-width: 0px ) {
+ @include cols(sm, 4)
}
-@include for-tablet-down {
- .md-col-span-0 {
- display: none;
- }
+@media ( min-width: 600px ) {
+ @include cols(md, 8)
}
-@include for-phone-down {
- .sm-col-span-0 {
- display: none;
- }
+@media ( min-width: 960px ) {
+ @include cols(lg, 12)
}
+
diff --git a/projects/js-packages/components/components/layout/container/index.jsx b/projects/js-packages/components/components/layout/container/index.jsx
index 221d769accb34..1c156f008e65e 100644
--- a/projects/js-packages/components/components/layout/container/index.jsx
+++ b/projects/js-packages/components/components/layout/container/index.jsx
@@ -2,6 +2,8 @@
* External dependencies
*/
import React from 'react';
+import classNames from 'classnames';
+import PropTypes from 'prop-types';
/**
* Internal dependencies
@@ -15,8 +17,43 @@ import styles from './style.module.scss';
* @returns {React.Component} Container component.
*/
const Container = props => {
- const { children } = props;
- return
{ children }
;
+ const { children, fluid, className } = props;
+
+ const horizontalSpacing = `calc( var(--horizontal-spacing) * ${ props.horizontalSpacing } )`;
+ const horizontalGap = `calc( var(--horizontal-spacing) * ${ props.horizontalGap } )`;
+
+ const containerStyle = {
+ paddingTop: horizontalSpacing,
+ paddingBottom: horizontalSpacing,
+ rowGap: horizontalGap,
+ };
+
+ const containerClassName = classNames( className, styles.container, {
+ [ styles.fluid ]: fluid,
+ } );
+
+ return (
+
+ { children }
+
+ );
+};
+
+Container.propTypes = {
+ /** Make container not having a max width. */
+ fluid: PropTypes.bool,
+ /** Custom className to be inserted. */
+ className: PropTypes.string,
+ /** Number of spacing (top / bottom), it gets mutiplied by 8px. Needs to be an integer */
+ horizontalSpacing: PropTypes.number,
+ /** Number of gap betwen rows, it gets multipled by 8px. Needs to be an integer */
+ horizontalGap: PropTypes.number,
+};
+
+Container.defaultProps = {
+ fluid: false,
+ horizontalGap: 1,
+ horizontalSpacing: 1,
};
export default Container;
diff --git a/projects/js-packages/components/components/layout/container/style.module.scss b/projects/js-packages/components/components/layout/container/style.module.scss
index d914ad02b4df0..9c983ee6939e2 100644
--- a/projects/js-packages/components/components/layout/container/style.module.scss
+++ b/projects/js-packages/components/components/layout/container/style.module.scss
@@ -1,7 +1,34 @@
-.jp-container {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- max-width: 1128px;
+@mixin container($columns, $width, $padding) {
+ @media ( min-width: #{$width} ) {
+ padding: 0 #{$padding};
+ grid-template-columns: repeat( #{$columns}, minmax(0, 1fr) );
+ }
+}
+
+.container {
+ --max-container-width: 1128px;
+
+ // vertical spacing
+ --vertical-gutter: 24px;
+ --vertical-spacing-sm: 16px;
+ --vertical-spacing-md: 18px;
+ --vertical-spacing-lg: 24px;
+
+ // horizontal spacing
+ --horizontal-spacing: 8px;
+
+ display: grid;
+ column-gap: var(--vertical-gutter);
+ max-width: var(--max-container-width);
margin: 0 auto;
+ width: 100%;
+
+ @include container( 4, 0px, var(--vertical-spacing-sm) );
+ @include container( 8, 600px, var(--vertical-spacing-md) );
+ @include container( 12, 960px, var(--vertical-spacing-lg) );
+
+ &.fluid {
+ max-width: none;
+ padding: unset;
+ }
}
diff --git a/projects/js-packages/components/components/layout/row/index.jsx b/projects/js-packages/components/components/layout/row/index.jsx
deleted file mode 100644
index 9d8e1dec37c78..0000000000000
--- a/projects/js-packages/components/components/layout/row/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * External dependencies
- */
-import React from 'react';
-
-/**
- * Internal dependencies
- */
-import styles from './style.module.scss';
-
-/**
- * JP Row
- *
- * @param {object} props - Component properties.
- * @returns {React.Component} Row component.
- */
-const Row = props => {
- const { children } = props;
- return
{ children }
;
-};
-
-export default Row;
diff --git a/projects/js-packages/components/components/layout/row/style.module.scss b/projects/js-packages/components/components/layout/row/style.module.scss
deleted file mode 100644
index 731a5e746b80b..0000000000000
--- a/projects/js-packages/components/components/layout/row/style.module.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-@import '@automattic/jetpack-base-styles/style';
-
-.jp-row {
- display: grid;
- grid-gap: 24px;
- grid-template-columns: repeat( 4, 1fr );
- width: 100%;
- margin: 0 16px;
-
- @include for-phone-up {
- grid-template-columns: repeat( 8, 1fr );
- margin: 0 18px;
- }
-
- @include for-tablet-up {
- grid-template-columns: repeat( 12, 1fr );
- max-width: 1128px;
- margin: 0 24px;
- }
-}
diff --git a/projects/js-packages/components/components/layout/stories/index.jsx b/projects/js-packages/components/components/layout/stories/index.jsx
new file mode 100644
index 0000000000000..382dcac644029
--- /dev/null
+++ b/projects/js-packages/components/components/layout/stories/index.jsx
@@ -0,0 +1,81 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+
+/**
+ * Internal dependencies
+ */
+import Container from '../container';
+import Col from '../col';
+import styles from './styles.module.scss';
+
+const Layout = ( { items, fluid, horizontalGap, horizontalSpacing } ) => {
+ return (
+
+ { items.map( ( { sm, lg, md } ) => (
+
+ { Number.isInteger( sm ) ? `sm=${ sm } ` : '' }
+ { Number.isInteger( md ) ? `md=${ md } ` : '' }
+ { Number.isInteger( lg ) ? `lg=${ lg } ` : '' }
+
+ ) ) }
+
+
+ Composition Example
+ Composition Example
+
+
+
+ );
+};
+
+export default {
+ title: 'Playground/Layout',
+ component: Layout,
+};
+
+const Template = args =>
;
+export const Default = Template.bind( {} );
+Default.args = {
+ fluid: false,
+ horizontalSpacing: 10,
+ horizontalGap: 5,
+ items: [
+ {
+ sm: 2,
+ md: 5,
+ lg: 4,
+ },
+ {
+ sm: 2,
+ md: 3,
+ lg: 8,
+ },
+ {
+ sm: 2,
+ md: 3,
+ lg: 8,
+ },
+ {
+ sm: 2,
+ md: 5,
+ lg: 4,
+ },
+ {
+ sm: 2,
+ md: 5,
+ lg: 4,
+ },
+ {
+ sm: 2,
+ md: 3,
+ lg: 8,
+ },
+ ],
+};
diff --git a/projects/js-packages/components/components/layout/stories/styles.module.scss b/projects/js-packages/components/components/layout/stories/styles.module.scss
new file mode 100644
index 0000000000000..5d02b35942615
--- /dev/null
+++ b/projects/js-packages/components/components/layout/stories/styles.module.scss
@@ -0,0 +1,10 @@
+.container {
+ background: var(--jp-gray-50);
+}
+
+.col {
+ padding: 20px;
+ background: var(--jp-gray-80);
+ font-size: 1rem;
+ color: var(--jp-white-off);
+}
diff --git a/projects/js-packages/components/index.jsx b/projects/js-packages/components/index.jsx
index dabd234c58852..493f150083452 100644
--- a/projects/js-packages/components/index.jsx
+++ b/projects/js-packages/components/index.jsx
@@ -27,6 +27,5 @@ export { default as AdminPage } from './components/admin-page';
export { default as DecorativeCard } from './components/decorative-card';
export { default as Col } from './components/layout/col';
export { default as Container } from './components/layout/container';
-export { default as Row } from './components/layout/row';
export { default as numberFormat } from './components/number-format';
export { getUserLocale, cleanLocale } from './lib/locale';
diff --git a/projects/js-packages/components/package.json b/projects/js-packages/components/package.json
index 51010020f841a..883b58ec8abce 100644
--- a/projects/js-packages/components/package.json
+++ b/projects/js-packages/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@automattic/jetpack-components",
- "version": "0.10.3",
+ "version": "0.10.4-alpha",
"description": "Jetpack Components Package",
"author": "Automattic",
"license": "GPL-2.0-or-later",
diff --git a/projects/js-packages/connection/changelog/update-my-jetpack-styles b/projects/js-packages/connection/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/js-packages/connection/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/js-packages/connection/package.json b/projects/js-packages/connection/package.json
index 9e5003d690cfe..864a07701d6a3 100644
--- a/projects/js-packages/connection/package.json
+++ b/projects/js-packages/connection/package.json
@@ -7,7 +7,7 @@
"dependencies": {
"@automattic/jetpack-analytics": "workspace:^0.1.7",
"@automattic/jetpack-config": "workspace:^0.1.3",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@automattic/jetpack-api": "workspace:^0.8.3",
"@wordpress/base-styles": "4.0.4",
"@wordpress/browserslist-config": "4.1.0",
diff --git a/projects/js-packages/idc/changelog/update-my-jetpack-styles b/projects/js-packages/idc/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/js-packages/idc/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/js-packages/idc/package.json b/projects/js-packages/idc/package.json
index 482060264ea58..a42387ecb830c 100644
--- a/projects/js-packages/idc/package.json
+++ b/projects/js-packages/idc/package.json
@@ -1,6 +1,6 @@
{
"name": "@automattic/jetpack-idc",
- "version": "0.9.0",
+ "version": "0.9.1-alpha",
"description": "Jetpack Connection Component",
"author": "Automattic",
"license": "GPL-2.0-or-later",
@@ -8,7 +8,7 @@
"@automattic/jetpack-analytics": "workspace:^0.1.7",
"@automattic/jetpack-api": "workspace:^0.8.3",
"@automattic/jetpack-base-styles": "workspace:^0.1.7",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@wordpress/base-styles": "4.0.4",
"@wordpress/components": "19.1.6",
"@wordpress/compose": "5.0.7",
diff --git a/projects/js-packages/licensing/changelog/update-my-jetpack-styles b/projects/js-packages/licensing/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/js-packages/licensing/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/js-packages/licensing/package.json b/projects/js-packages/licensing/package.json
index 579cd9a463d02..c4e6ce2accef5 100644
--- a/projects/js-packages/licensing/package.json
+++ b/projects/js-packages/licensing/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@automattic/jetpack-licensing",
- "version": "0.4.4",
+ "version": "0.4.5-alpha",
"description": "Jetpack licensing flow",
"homepage": "https://jetpack.com",
"bugs": {
@@ -37,7 +37,7 @@
},
"dependencies": {
"@automattic/jetpack-api": "workspace:^0.8.3",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@wordpress/i18n": "4.2.4",
"@wordpress/element": "4.0.4",
"prop-types": "15.7.2",
diff --git a/projects/js-packages/partner-coupon/changelog/update-my-jetpack-styles b/projects/js-packages/partner-coupon/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/js-packages/partner-coupon/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/js-packages/partner-coupon/package.json b/projects/js-packages/partner-coupon/package.json
index a625139ba536a..6cf6c944ba34d 100644
--- a/projects/js-packages/partner-coupon/package.json
+++ b/projects/js-packages/partner-coupon/package.json
@@ -28,7 +28,7 @@
},
"dependencies": {
"@automattic/jetpack-connection": "workspace:^0.15.0-alpha",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@wordpress/i18n": "4.2.4",
"classnames": "2.3.1",
"prop-types": "15.7.2"
diff --git a/projects/js-packages/shared-extension-utils/changelog/update-shared-extension-utils-prepare-release b/projects/js-packages/shared-extension-utils/changelog/update-shared-extension-utils-prepare-release
new file mode 100644
index 0000000000000..df7ae220b753e
--- /dev/null
+++ b/projects/js-packages/shared-extension-utils/changelog/update-shared-extension-utils-prepare-release
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Core: prepare utility for release
diff --git a/projects/js-packages/shared-extension-utils/composer.json b/projects/js-packages/shared-extension-utils/composer.json
index f60d568dfcb3b..5e88b1125fe17 100644
--- a/projects/js-packages/shared-extension-utils/composer.json
+++ b/projects/js-packages/shared-extension-utils/composer.json
@@ -26,5 +26,13 @@
}
],
"minimum-stability": "dev",
- "prefer-stable": true
+ "prefer-stable": true,
+ "extra": {
+ "autotagger": true,
+ "npmjs-autopublish": true,
+ "mirror-repo": "Automattic/jetpack-shared-extension-utils",
+ "changelogger": {
+ "link-template": "https://github.com/Automattic/jetpack-shared-extension-utils/compare/${old}...${new}"
+ }
+ }
}
diff --git a/projects/js-packages/shared-extension-utils/package.json b/projects/js-packages/shared-extension-utils/package.json
index dce5717662b07..c05e0bfd3ef22 100644
--- a/projects/js-packages/shared-extension-utils/package.json
+++ b/projects/js-packages/shared-extension-utils/package.json
@@ -1,5 +1,4 @@
{
- "private": true,
"name": "@automattic/jetpack-shared-extension-utils",
"version": "0.1.0-alpha",
"description": "Utility functions used by the block editor extensions",
diff --git a/projects/packages/identity-crisis/changelog/update-my-jetpack-styles b/projects/packages/identity-crisis/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/packages/identity-crisis/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/packages/identity-crisis/package.json b/projects/packages/identity-crisis/package.json
index 119c87fae0f62..0bc289810fdac 100644
--- a/projects/packages/identity-crisis/package.json
+++ b/projects/packages/identity-crisis/package.json
@@ -1,6 +1,6 @@
{
"name": "jetpack-identity-crisis",
- "version": "0.7.0",
+ "version": "0.7.1-alpha",
"description": "Jetpack Identity Crisis",
"main": "_inc/admin.jsx",
"repository": "https://github.com/Automattic/jetpack-identity-crisis",
@@ -15,7 +15,7 @@
},
"browserslist": "extends @wordpress/browserslist-config",
"dependencies": {
- "@automattic/jetpack-idc": "workspace:^0.9.0",
+ "@automattic/jetpack-idc": "workspace:^0.9.1-alpha",
"@wordpress/data": "6.1.5"
},
"devDependencies": {
diff --git a/projects/packages/identity-crisis/src/class-identity-crisis.php b/projects/packages/identity-crisis/src/class-identity-crisis.php
index 22f775ba754d2..98f66f00b9d55 100644
--- a/projects/packages/identity-crisis/src/class-identity-crisis.php
+++ b/projects/packages/identity-crisis/src/class-identity-crisis.php
@@ -28,7 +28,7 @@ class Identity_Crisis {
/**
* Package Version
*/
- const PACKAGE_VERSION = '0.7.0';
+ const PACKAGE_VERSION = '0.7.1-alpha';
/**
* Instance of the object.
diff --git a/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx b/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx
index c653aafb4ae07..671bfede4589a 100644
--- a/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx
+++ b/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx
@@ -1,10 +1,9 @@
-/* global myJetpackRest */
-/* global myJetpackInitialState */
/**
* External dependencies
*/
-import React, { useCallback } from 'react';
+import React from 'react';
import { ConnectionStatusCard } from '@automattic/jetpack-connection';
+import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
/**
* Plan section component.
@@ -12,16 +11,8 @@ import { ConnectionStatusCard } from '@automattic/jetpack-connection';
* @returns {object} ConnectionsSection React component.
*/
export default function ConnectionsSection() {
- const { apiRoot, apiNonce } = myJetpackRest;
- const redirectAfterDisconnect = useCallback( () => {
- window.location = myJetpackInitialState.topJetpackMenuItemUrl;
- }, [] );
+ const { apiRoot, apiNonce, redirectUrl } = useMyJetpackConnection();
return (
-
+
);
}
diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx
index 4f0db5a7ea1c2..d724421f3fe77 100644
--- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx
+++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx
@@ -9,7 +9,7 @@ import {
AdminSection,
AdminSectionHero,
AdminPage,
- Row,
+ Container,
Col,
} from '@automattic/jetpack-components';
@@ -21,17 +21,10 @@ import PlansSection from '../plans-section';
import ProductCardsSection from '../product-cards-section';
import useAnalytics from '../../hooks/use-analytics';
import useNoticeWatcher, { useGlobalNotice } from '../../hooks/use-notice';
-import './style.scss';
-
-/**
- * Component that renders the My Jetpack global notices.
- *
- * @returns {object} The GlobalNotice component.
- */
-function GlobalNotice() {
- // Watch global events.
- useNoticeWatcher();
+import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
+import styles from './styles.module.scss';
+const GlobalNotice = ( { message, options, clean } ) => {
/*
* Map Notice statuses with Icons.
* `success`, `info`, `warning`, `error`
@@ -41,18 +34,13 @@ function GlobalNotice() {
info,
};
- const { message, options, clean } = useGlobalNotice();
- if ( ! message ) {
- return null;
- }
-
return (
{ iconMap?.[ options.status ] && }
{ message }
);
-}
+};
/**
* The My Jetpack App Main Screen.
@@ -60,46 +48,57 @@ function GlobalNotice() {
* @returns {object} The MyJetpackScreen component.
*/
export default function MyJetpackScreen() {
+ useNoticeWatcher();
+ const { message, options, clean } = useGlobalNotice();
+
const {
tracks: { recordEvent },
} = useAnalytics();
+
useEffect( () => {
recordEvent( 'jetpack_myjetpack_page_view' );
}, [ recordEvent ] );
+ // No render when site is not connected.
+ const { isSiteConnected } = useMyJetpackConnection( { redirect: true } );
+
+ if ( ! isSiteConnected ) {
+ return null;
+ }
+
return (
-
-
-
-
-
-
- { __(
- 'Manage your Jetpack plan and products all in one place',
- 'jetpack-my-jetpack'
- ) }
-
-
-
-
-
-
-
+
+
+
+
+
+ { __(
+ 'Manage your Jetpack plan and products all in one place',
+ 'jetpack-my-jetpack'
+ ) }
+
+
+ { message && (
+
+
-
-
+ ) }
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/style.scss b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/style.scss
deleted file mode 100644
index 430bfe51c91ad..0000000000000
--- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/style.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-@import '@automattic/jetpack-base-styles/style';
-
-.components-notice {
- margin: 20px 0;
-
- .components-notice__content {
- display: flex;
-
- .components-notice__message-content {
- height: 24px;
- line-height: 24px;
- margin-left: 10px;
- }
- }
-
- .components-notice__action.components-button.is-link {
- color: var( --jp-black );
- font-weight: 600;
- }
-}
diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss
new file mode 100644
index 0000000000000..bf1745a22b5b8
--- /dev/null
+++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/styles.module.scss
@@ -0,0 +1,28 @@
+@import '@automattic/jetpack-base-styles/style';
+
+.heading {
+ font-size: 36px;
+ line-height: 40px;
+ margin: 0;
+}
+
+:global {
+ .components-notice {
+ margin: 0;
+
+ .components-notice__content {
+ display: flex;
+
+ .components-notice__message-content {
+ height: 24px;
+ line-height: 24px;
+ margin-left: 10px;
+ }
+ }
+
+ .components-notice__action.components-button.is-link {
+ color: var( --jp-black );
+ font-weight: 600;
+ }
+ }
+}
diff --git a/projects/packages/my-jetpack/_inc/components/product-card/index.jsx b/projects/packages/my-jetpack/_inc/components/product-card/index.jsx
index b715b15302783..fbcf70bc453c8 100644
--- a/projects/packages/my-jetpack/_inc/components/product-card/index.jsx
+++ b/projects/packages/my-jetpack/_inc/components/product-card/index.jsx
@@ -148,7 +148,7 @@ const ProductCard = props => {
{ description }
{ canDeactivate ? (
-
+
{ renderActionButton( { ...props, onActivate: activateHandler } ) }
{
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.js b/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.js
index c5d71bc1d91ef..d33504b9636e0 100644
--- a/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.js
+++ b/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.js
@@ -1,20 +1,14 @@
-/* global myJetpackRest */
/**
* External dependencies
*/
import { useEffect } from 'react';
import jetpackAnalytics from '@automattic/jetpack-analytics';
-import { useConnection } from '@automattic/jetpack-connection';
+import useMyJetpackConnection from '../use-my-jetpack-connection';
const useAnalytics = () => {
- const { apiRoot, apiNonce } = myJetpackRest;
-
- const { isUserConnected, userConnectionData } = useConnection( {
- apiRoot,
- apiNonce,
- } );
-
+ const { isUserConnected, userConnectionData } = useMyJetpackConnection();
const { login, ID } = userConnectionData.currentUser.wpcomUser;
+
/**
* Initialize tracks with user data.
* Should run when we have a connected user.
diff --git a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.js b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.js
new file mode 100644
index 0000000000000..f04ad8d947b17
--- /dev/null
+++ b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.js
@@ -0,0 +1,56 @@
+/* global myJetpackInitialState */
+/* global myJetpackRest */
+/**
+ * WordPress dependencies
+ */
+import { useEffect } from 'react';
+import { useConnection } from '@automattic/jetpack-connection';
+
+/**
+ * React custom hook to get the site purchases data.
+ *
+ * @param {object} options - Options to pass to the hook.
+ * @param {boolean} options.reditect - Perform a redirect when no connection is found.
+ * @returns {object} site purchases data
+ */
+export default function useMyJetpackConnection( options = { redirect: false } ) {
+ const { apiRoot, apiNonce } = myJetpackRest;
+ const { topJetpackMenuItemUrl } = myJetpackInitialState;
+ const { redirect } = options;
+ const connectionData = useConnection( { apiRoot, apiNonce } );
+
+ // Alias: https://github.com/Automattic/jetpack/blob/master/projects/packages/connection/src/class-rest-connector.php/#L315
+ const isSiteConnected = connectionData.isRegistered;
+
+ /*
+ * When the site is not connect,
+ * and the `redirect` option is set to `true`,
+ * redirect to the Jetpack dashboard.
+ */
+ useEffect( () => {
+ // Bail early when topJetpackMenuItemUrl is not defined.
+ if ( ! topJetpackMenuItemUrl ) {
+ return;
+ }
+
+ // Bail early when redirect mode is disabled.
+ if ( ! redirect ) {
+ return;
+ }
+
+ // When site is connected, bail early.
+ if ( isSiteConnected ) {
+ return;
+ }
+
+ window.location = topJetpackMenuItemUrl;
+ }, [ isSiteConnected, redirect, topJetpackMenuItemUrl ] );
+
+ return {
+ apiNonce,
+ apiRoot,
+ ...connectionData,
+ isSiteConnected,
+ redirectUrl: topJetpackMenuItemUrl,
+ };
+}
diff --git a/projects/packages/my-jetpack/_inc/hooks/use-notice/index.js b/projects/packages/my-jetpack/_inc/hooks/use-notice/index.js
index b8473771dd30b..4c4ae629977da 100644
--- a/projects/packages/my-jetpack/_inc/hooks/use-notice/index.js
+++ b/projects/packages/my-jetpack/_inc/hooks/use-notice/index.js
@@ -1,16 +1,15 @@
-/* global myJetpackRest */
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
-import { useConnection } from '@automattic/jetpack-connection';
import { useSelect, useDispatch } from '@wordpress/data';
/**
* Internal dependencies
*/
import { STORE_ID } from '../../state/store';
+import useMyJetpackConnection from '../use-my-jetpack-connection';
/**
* React custom hook to get global notices.
@@ -34,13 +33,8 @@ export function useGlobalNotice() {
* the hook dispatches an action to populate the global notice.
*/
export default function useNoticeWatcher() {
- const { apiRoot, apiNonce } = myJetpackRest;
const dispatch = useDispatch();
-
- const { isUserConnected } = useConnection( {
- apiRoot,
- apiNonce,
- } );
+ const { isUserConnected, redirectUrl } = useMyJetpackConnection();
useEffect( () => {
if ( ! isUserConnected ) {
@@ -54,11 +48,11 @@ export default function useNoticeWatcher() {
actions: [
{
label: __( 'Connect Jetpack now.', 'jetpack-my-jetpack' ),
- url: '#',
+ url: redirectUrl,
},
],
}
);
}
- }, [ isUserConnected, dispatch ] );
+ }, [ isUserConnected, dispatch, redirectUrl ] );
}
diff --git a/projects/packages/my-jetpack/changelog/add-hide-my-jetpack-not-connected-site b/projects/packages/my-jetpack/changelog/add-hide-my-jetpack-not-connected-site
new file mode 100644
index 0000000000000..64548e21c053e
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/add-hide-my-jetpack-not-connected-site
@@ -0,0 +1,4 @@
+Significance: minor
+Type: changed
+
+Do not initialize My Jetpack id site is not connected
diff --git a/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests b/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests
new file mode 100644
index 0000000000000..c04953f478221
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Fix tests
diff --git a/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests#2 b/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests#2
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/fix-my-jetpack-tests#2
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-handle-when-no-site-connected b/projects/packages/my-jetpack/changelog/update-my-jetpack-handle-when-no-site-connected
new file mode 100644
index 0000000000000..021102a890067
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-handle-when-no-site-connected
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Handle when site is not connected
diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-remove-connections-section b/projects/packages/my-jetpack/changelog/update-my-jetpack-remove-connections-section
new file mode 100644
index 0000000000000..1273531e251be
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-remove-connections-section
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+My Jetpack: handle redirect when no connection #22549
diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-styles b/projects/packages/my-jetpack/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..0179615c2e85c
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+My Jetpack: Refactor styles to use layout components and theme provider
diff --git a/projects/packages/my-jetpack/changelog/update-my-jetpack-styles#2 b/projects/packages/my-jetpack/changelog/update-my-jetpack-styles#2
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/update-my-jetpack-styles#2
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/packages/my-jetpack/composer.json b/projects/packages/my-jetpack/composer.json
index 1c9deb42c30d5..fb8664650ca3e 100644
--- a/projects/packages/my-jetpack/composer.json
+++ b/projects/packages/my-jetpack/composer.json
@@ -14,6 +14,7 @@
"require-dev": {
"yoast/phpunit-polyfills": "1.0.3",
"automattic/jetpack-changelogger": "^3.0",
+ "automattic/jetpack-options": "^1.14",
"automattic/wordbless": "@dev"
},
"autoload": {
diff --git a/projects/packages/my-jetpack/package.json b/projects/packages/my-jetpack/package.json
index 6ddd530b01a7a..8ac7b26fe6df5 100644
--- a/projects/packages/my-jetpack/package.json
+++ b/projects/packages/my-jetpack/package.json
@@ -22,8 +22,9 @@
},
"dependencies": {
"@automattic/jetpack-analytics": "workspace:^0.1.7",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@automattic/jetpack-connection": "workspace:^0.15.0-alpha",
+ "@wordpress/api-fetch": "6.0.0",
"@wordpress/components": "19.1.6",
"@wordpress/data": "6.1.5",
"@wordpress/i18n": "4.2.4",
diff --git a/projects/packages/my-jetpack/src/class-initializer.php b/projects/packages/my-jetpack/src/class-initializer.php
index e46a4dc9453b7..93cd1557dd3d7 100644
--- a/projects/packages/my-jetpack/src/class-initializer.php
+++ b/projects/packages/my-jetpack/src/class-initializer.php
@@ -37,6 +37,11 @@ public static function init() {
return;
}
+ // Do not initialize My Jetpack if site is not connected.
+ if ( ! ( new Connection_Manager() )->is_connected() ) {
+ return;
+ }
+
// Set up the REST authentication hooks.
Connection_Rest_Authentication::init();
diff --git a/projects/packages/my-jetpack/tests/php/test-products-rest.php b/projects/packages/my-jetpack/tests/php/test-products-rest.php
index c927eb51a8393..b9a2171e8b480 100644
--- a/projects/packages/my-jetpack/tests/php/test-products-rest.php
+++ b/projects/packages/my-jetpack/tests/php/test-products-rest.php
@@ -2,6 +2,8 @@
namespace Automattic\Jetpack\My_Jetpack;
+use Automattic\Jetpack\Connection\Tokens;
+use Jetpack_Options;
use PHPUnit\Framework\TestCase;
use WorDBless\Options as WorDBless_Options;
use WorDBless\Users as WorDBless_Users;
@@ -60,6 +62,10 @@ public function set_up() {
$this->install_mock_plugin();
+ // Mock site connection.
+ ( new Tokens() )->update_blog_token( 'test.test.1' );
+ Jetpack_Options::update_option( 'id', 123 );
+
global $wp_rest_server;
$wp_rest_server = new WP_REST_Server();
diff --git a/projects/packages/search/CHANGELOG.md b/projects/packages/search/CHANGELOG.md
index 5abeb81da6c73..db115f51ccf70 100644
--- a/projects/packages/search/CHANGELOG.md
+++ b/projects/packages/search/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.5.4] - 2022-01-31
+### Fixed
+- Search: Fetch plan info as blog, not as user, to allow nonconnected admins to use dashboard
+
## [0.5.3] - 2022-01-27
### Fixed
- Search package: fixed compatibility issue with plan activation
@@ -74,6 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated package dependencies.
- Update PHPUnit configs to include just what needs coverage rather than include everything then try to exclude stuff that doesn't.
+[0.5.4]: https://github.com/Automattic/jetpack-search/compare/v0.5.3...v0.5.4
[0.5.3]: https://github.com/Automattic/jetpack-search/compare/v0.5.2...v0.5.3
[0.5.2]: https://github.com/Automattic/jetpack-search/compare/v0.5.1...v0.5.2
[0.5.1]: https://github.com/Automattic/jetpack-search/compare/v0.5.0...v0.5.1
diff --git a/projects/packages/search/changelog/update-my-jetpack-styles b/projects/packages/search/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/packages/search/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/packages/search/package.json b/projects/packages/search/package.json
index ccc7c97f541fa..84da17e7b344e 100644
--- a/projects/packages/search/package.json
+++ b/projects/packages/search/package.json
@@ -40,7 +40,7 @@
"@automattic/color-studio": "2.5.0",
"@automattic/jetpack-analytics": "workspace:^0.1.7",
"@automattic/jetpack-api": "workspace:^0.8.3",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@wordpress/base-styles": "4.0.4",
"@wordpress/block-editor": "8.0.12",
"@wordpress/data": "6.1.5",
diff --git a/projects/packages/search/src/class-plan.php b/projects/packages/search/src/class-plan.php
index b02ad89a54baa..4748653058879 100644
--- a/projects/packages/search/src/class-plan.php
+++ b/projects/packages/search/src/class-plan.php
@@ -43,9 +43,12 @@ public function init_hooks() {
*/
public function get_plan_info_from_wpcom() {
$blog_id = Jetpack_Options::get_option( 'id' );
- $response = Client::wpcom_json_api_request_as_user(
+ $response = Client::wpcom_json_api_request_as_blog(
'/sites/' . $blog_id . '/jetpack-search/plan',
- '2'
+ '2',
+ array(),
+ null,
+ 'wpcom'
);
// store plan in options.
diff --git a/projects/plugins/backup/changelog/fix-my-jetpack-tests b/projects/plugins/backup/changelog/fix-my-jetpack-tests
new file mode 100644
index 0000000000000..9aa70e3ec1f75
--- /dev/null
+++ b/projects/plugins/backup/changelog/fix-my-jetpack-tests
@@ -0,0 +1,5 @@
+Significance: patch
+Type: changed
+Comment: Updated composer.lock.
+
+
diff --git a/projects/plugins/backup/changelog/update-my-jetpack-styles b/projects/plugins/backup/changelog/update-my-jetpack-styles
new file mode 100644
index 0000000000000..c47cb18e82997
--- /dev/null
+++ b/projects/plugins/backup/changelog/update-my-jetpack-styles
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Updated package dependencies.
diff --git a/projects/plugins/backup/composer.lock b/projects/plugins/backup/composer.lock
index 0c5532321a6f6..ddddce434fe4b 100644
--- a/projects/plugins/backup/composer.lock
+++ b/projects/plugins/backup/composer.lock
@@ -777,7 +777,7 @@
"dist": {
"type": "path",
"url": "../../packages/my-jetpack",
- "reference": "56f7774f2d6193d2a1691e8b59dfe20fe5a2459c"
+ "reference": "5ca3f982d2e026a0b72c4965a349812f9e321677"
},
"require": {
"automattic/jetpack-admin-ui": "^0.2",
@@ -789,6 +789,7 @@
},
"require-dev": {
"automattic/jetpack-changelogger": "^3.0",
+ "automattic/jetpack-options": "^1.14",
"automattic/wordbless": "@dev",
"yoast/phpunit-polyfills": "1.0.3"
},
diff --git a/projects/plugins/backup/package.json b/projects/plugins/backup/package.json
index 35ce50142170c..145c61854f6c5 100644
--- a/projects/plugins/backup/package.json
+++ b/projects/plugins/backup/package.json
@@ -25,7 +25,7 @@
],
"dependencies": {
"@automattic/jetpack-api": "workspace:^0.8.3",
- "@automattic/jetpack-components": "workspace:^0.10.3",
+ "@automattic/jetpack-components": "workspace:^0.10.4-alpha",
"@automattic/jetpack-connection": "workspace:^0.15.0-alpha",
"@wordpress/api-fetch": "5.2.6",
"@wordpress/data": "6.1.5",
diff --git a/projects/plugins/backup/src/js/components/Admin.js b/projects/plugins/backup/src/js/components/Admin.js
index 2724a00d0c7dd..1398091f32028 100644
--- a/projects/plugins/backup/src/js/components/Admin.js
+++ b/projects/plugins/backup/src/js/components/Admin.js
@@ -9,7 +9,7 @@ import {
AdminPage,
AdminSection,
AdminSectionHero,
- Row,
+ Container,
Col,
getRedirectUrl,
PricingCard,
@@ -84,7 +84,7 @@ const Admin = () => {
'jetpack-backup'
);
return (
-
+
{ __( 'Secure your site with a Backup subscription.', 'jetpack-backup' ) }
@@ -115,7 +115,7 @@ const Admin = () => {
title={ __( 'Jetpack Backup', 'jetpack-backup' ) }
/>
-
+
);
};
@@ -130,11 +130,11 @@ const Admin = () => {
}
return (
-
+
{ renderConnectScreen() }
-
+
);
}
@@ -154,11 +154,11 @@ const Admin = () => {
// Render an error state, this shouldn't occurr since we've passed userConnected checks
if ( capabilitiesError ) {
return (
-
+
{ capabilitiesError }
-
+
);
}
@@ -168,7 +168,7 @@ const Admin = () => {
// Renders additional segments under the jp-hero area condition on having a backup plan
const renderBackupSegments = () => {
return (
-
+
{ __( 'Your cloud backups', 'jetpack-backup' ) }
@@ -218,7 +218,7 @@ const Admin = () => {
{ renderConnectionStatusCard() }
-
+
);
};
diff --git a/projects/plugins/boost/.phpcs.dir.xml b/projects/plugins/boost/.phpcs.dir.xml
index de9dcf15a11a6..0d50ca55e7c99 100644
--- a/projects/plugins/boost/.phpcs.dir.xml
+++ b/projects/plugins/boost/.phpcs.dir.xml
@@ -21,4 +21,38 @@
+
+ 0
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/plugins/boost/app/admin/class-admin.php b/projects/plugins/boost/app/admin/class-admin.php
index 014fc768c3b77..4cfe6eb0e9b69 100644
--- a/projects/plugins/boost/app/admin/class-admin.php
+++ b/projects/plugins/boost/app/admin/class-admin.php
@@ -10,14 +10,14 @@
use Automattic\Jetpack\Admin_UI\Admin_Menu;
use Automattic\Jetpack\Status;
+use Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS\Critical_CSS;
+use Automattic\Jetpack_Boost\Features\Optimizations\Optimizations;
+use Automattic\Jetpack_Boost\Features\Speed_Score\Speed_Score;
use Automattic\Jetpack_Boost\Jetpack_Boost;
use Automattic\Jetpack_Boost\Lib\Analytics;
use Automattic\Jetpack_Boost\Lib\Environment_Change_Detector;
-use Automattic\Jetpack_Boost\Lib\Speed_Score;
+use Automattic\Jetpack_Boost\REST_API\Permissions\Nonce;
-/**
- * Class Admin
- */
class Admin {
/**
@@ -45,7 +45,7 @@ class Admin {
*
* @var Jetpack_Boost Plugin.
*/
- private $jetpack_boost;
+ private $modules;
/**
* Speed_Score class instance.
@@ -54,21 +54,13 @@ class Admin {
*/
private $speed_score;
- /**
- * Initialize the class and set its properties.
- *
- * @param Jetpack_Boost $jetpack_boost Main plugin instance.
- *
- * @since 1.0.0
- */
- public function __construct( Jetpack_Boost $jetpack_boost ) {
- $this->jetpack_boost = $jetpack_boost;
- $this->speed_score = new Speed_Score( $jetpack_boost );
+ public function __construct( Optimizations $modules ) {
+ $this->modules = $modules;
+ $this->speed_score = new Speed_Score( $modules );
Environment_Change_Detector::init();
add_action( 'init', array( new Analytics(), 'init' ) );
add_filter( 'plugin_action_links_' . JETPACK_BOOST_PLUGIN_BASE, array( $this, 'plugin_page_settings_link' ) );
- add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );
add_action( 'admin_notices', array( $this, 'show_notices' ) );
add_action( 'wp_ajax_set_show_rating_prompt', array( $this, 'handle_set_show_rating_prompt' ) );
add_filter( 'jetpack_boost_js_constants', array( $this, 'add_js_constants' ) );
@@ -102,7 +94,7 @@ public function enqueue_styles() {
$internal_path = apply_filters( 'jetpack_boost_asset_internal_path', 'app/assets/dist/' );
wp_enqueue_style(
- $this->jetpack_boost->get_plugin_name() . '-css',
+ 'jetpack-boost-css',
plugins_url( $internal_path . 'jetpack-boost.css', JETPACK_BOOST_PATH ),
array( 'wp-components' ),
JETPACK_BOOST_VERSION
@@ -117,7 +109,7 @@ public function enqueue_styles() {
public function enqueue_scripts() {
$internal_path = apply_filters( 'jetpack_boost_asset_internal_path', 'app/assets/dist/' );
- $admin_js_handle = $this->jetpack_boost->get_plugin_name() . '-admin';
+ $admin_js_handle = 'jetpack-boost-admin';
wp_register_script(
$admin_js_handle,
@@ -127,6 +119,7 @@ public function enqueue_scripts() {
true
);
+ $optimizations = ( new Optimizations() )->get_status();
// Prepare configuration constants for JavaScript.
$constants = array(
'version' => JETPACK_BOOST_VERSION,
@@ -134,8 +127,7 @@ public function enqueue_scripts() {
'namespace' => JETPACK_BOOST_REST_NAMESPACE,
'prefix' => JETPACK_BOOST_REST_PREFIX,
),
- 'modules' => $this->jetpack_boost->get_available_modules(),
- 'config' => $this->jetpack_boost->config()->get_data(),
+ 'optimizations' => $optimizations,
'locale' => get_locale(),
'site' => array(
'url' => get_home_url(),
@@ -146,6 +138,14 @@ public function enqueue_scripts() {
'preferences' => array(
'showRatingPrompt' => $this->get_show_rating_prompt(),
),
+
+ /**
+ * A bit of necessary magic,
+ * Explained more in the Nonce class.
+ *
+ * Nonces are automatically generated when registering routes.
+ */
+ 'nonces' => Nonce::get_generated_nonces(),
);
// Give each module an opportunity to define extra constants.
@@ -179,7 +179,7 @@ public function plugin_page_settings_link( $links ) {
*/
public function render_settings() {
wp_localize_script(
- $this->jetpack_boost->get_plugin_name() . '-admin',
+ 'jetpack-boost-admin',
'wpApiSettings',
array(
'root' => esc_url_raw( rest_url() ),
@@ -200,49 +200,6 @@ public function check_for_permissions() {
return current_user_can( 'manage_options' );
}
- /**
- * Register REST routes for settings.
- *
- * @return void
- */
- public function register_rest_routes() {
- // Activate and deactivate a module.
- register_rest_route(
- JETPACK_BOOST_REST_NAMESPACE,
- JETPACK_BOOST_REST_PREFIX . '/module/(?P[a-z\-]+)/status',
- array(
- 'methods' => \WP_REST_Server::EDITABLE,
- 'callback' => array( $this, 'set_module_status' ),
- 'permission_callback' => array( $this, 'check_for_permissions' ),
- )
- );
- }
-
- /**
- * Handler for the /module/(?P[a-z\-]+)/status endpoint.
- *
- * @param \WP_REST_Request $request The request object.
- *
- * @return \WP_REST_Response|\WP_Error The response.
- */
- public function set_module_status( $request ) {
- $params = $request->get_json_params();
-
- if ( ! isset( $params['status'] ) ) {
- return new \WP_Error(
- 'jetpack_boost_error_missing_module_status_param',
- __( 'Missing status param', 'jetpack-boost' )
- );
- }
-
- $module_slug = $request['slug'];
- $this->jetpack_boost->set_module_status( (bool) $params['status'], $module_slug );
-
- return rest_ensure_response(
- $this->jetpack_boost->get_module_status( $module_slug )
- );
- }
-
/**
* Show any admin notices from enabled modules.
*/
@@ -250,7 +207,7 @@ public function show_notices() {
// Determine if we're already on the settings page.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$on_settings_page = isset( $_GET['page'] ) && self::MENU_SLUG === $_GET['page'];
- $notices = $this->jetpack_boost->get_admin_notices();
+ $notices = $this->get_admin_notices();
// Filter out any that have been dismissed, unless newer than the dismissal.
$dismissed_notices = \get_option( self::DISMISSED_NOTICE_OPTION, array() );
@@ -281,7 +238,7 @@ function ( $notice ) use ( $dismissed_notices ) {
* @return array List of notice ids.
*/
private function get_shown_admin_notice_ids() {
- $notices = $this->jetpack_boost->get_admin_notices();
+ $notices = $this->get_admin_notices();
$ids = array();
foreach ( $notices as $notice ) {
$ids[] = $notice->get_id();
@@ -290,6 +247,18 @@ private function get_shown_admin_notice_ids() {
return $ids;
}
+ /**
+ * Returns a list of admin notices to show. Asks each module to provide admin notices the user needs to see.
+ *
+ * @TODO: This is still a code smell. We're carrying the whole modules instance just to get a list of admin notices.
+ *
+ * @return \Automattic\Jetpack_Boost\Admin\Admin_Notice[]
+ */
+ public function get_admin_notices() {
+ $critical_css = new Critical_CSS();
+ return $critical_css->get_admin_notices();
+ }
+
/**
* Check for a GET parameter used to dismiss an admin notice.
*
diff --git a/projects/plugins/boost/app/assets/src/js/global.d.ts b/projects/plugins/boost/app/assets/src/js/global.d.ts
index 16d75ef98e167..b341177e5a5a8 100644
--- a/projects/plugins/boost/app/assets/src/js/global.d.ts
+++ b/projects/plugins/boost/app/assets/src/js/global.d.ts
@@ -12,7 +12,7 @@ import type { BrowserInterfaceIframe, generateCriticalCSS } from 'jetpack-boost-
*/
import type { ConnectionStatus } from './stores/connection';
import type { CriticalCssStatus } from './stores/critical-css-status';
-import type { ModulesState } from './stores/modules';
+import type { Optimizations } from './stores/modules';
declare global {
const wpApiSettings: {
@@ -35,15 +35,17 @@ declare global {
connection: ConnectionStatus;
criticalCssStatus?: CriticalCssStatus;
showRatingPromptNonce?: string;
- criticalCssDismissRecommendationsNonce?: string;
criticalCssDismissedRecommendations: string[];
site: {
url: string;
online: boolean;
assetPath: string;
};
- config: ModulesState;
+ optimizations: Optimizations;
shownAdminNoticeIds: string[];
+ nonces: {
+ [ key: string ]: string;
+ };
};
// Critical CSS Generator library.
diff --git a/projects/plugins/boost/app/assets/src/js/stores/critical-css-recommendations.ts b/projects/plugins/boost/app/assets/src/js/stores/critical-css-recommendations.ts
index 4f80206670bc4..b6c98fe8d5aac 100644
--- a/projects/plugins/boost/app/assets/src/js/stores/critical-css-recommendations.ts
+++ b/projects/plugins/boost/app/assets/src/js/stores/critical-css-recommendations.ts
@@ -6,11 +6,11 @@ import { writable, derived } from 'svelte/store';
/**
* Internal dependencies
*/
+import api from '../api/api';
import { CriticalCssErrorDetails, criticalCssStatus } from './critical-css-status';
import type { JSONObject } from '../utils/json-types';
import { objectFilter } from '../utils/object-filter';
import { sortByFrequency } from '../utils/sort-by-frequency';
-import { makeAdminAjaxRequest } from '../utils/make-admin-ajax-request';
import { castToString } from '../utils/cast-to-string';
const importantProviders = [
@@ -118,10 +118,9 @@ export function setDismissalError( title: string, error: JSONObject ): void {
* @param {string} key Key of recommendation to dismiss.
*/
export async function dismissRecommendation( key: string ): Promise< void > {
- await makeAdminAjaxRequest( {
- action: 'dismiss_recommendations',
+ await api.post( '/recommendations/dismiss', {
providerKey: key,
- nonce: Jetpack_Boost.criticalCssDismissRecommendationsNonce,
+ nonce: Jetpack_Boost.nonces[ 'recommendations/dismiss' ],
} );
dismissed.update( keys => [ ...keys, key ] );
}
@@ -130,9 +129,8 @@ export async function dismissRecommendation( key: string ): Promise< void > {
* Clear all the dismissed recommendations.
*/
export async function clearDismissedRecommendations(): Promise< void > {
- await makeAdminAjaxRequest( {
- action: 'reset_dismissed_recommendations',
- nonce: Jetpack_Boost.criticalCssDismissRecommendationsNonce,
+ await api.post( '/recommendations/reset', {
+ nonce: Jetpack_Boost.nonces[ 'recommendations/reset' ],
} );
dismissed.set( [] );
}
diff --git a/projects/plugins/boost/app/assets/src/js/stores/modules.ts b/projects/plugins/boost/app/assets/src/js/stores/modules.ts
index f9accfb9b2544..668f0771c61e6 100644
--- a/projects/plugins/boost/app/assets/src/js/stores/modules.ts
+++ b/projects/plugins/boost/app/assets/src/js/stores/modules.ts
@@ -9,6 +9,10 @@ import { writable } from 'svelte/store';
import config from './config';
import { setModuleState } from '../api/modules';
+export type Optimizations = {
+ [ slug: string ]: boolean;
+};
+
export type ModulesState = {
[ slug: string ]: {
enabled: boolean;
@@ -16,7 +20,13 @@ export type ModulesState = {
};
};
-const initialState = config.config;
+const initialState = {};
+for ( const [ name, value ] of Object.entries( config.optimizations ) ) {
+ initialState[ name ] = {
+ enabled: value,
+ };
+}
+
const { subscribe, update } = writable< ModulesState >( initialState );
// Keep a subscribed copy for quick reading.
diff --git a/projects/plugins/boost/app/assets/src/js/utils/generate-critical-css.ts b/projects/plugins/boost/app/assets/src/js/utils/generate-critical-css.ts
index 9e931710023bb..a76d34c2321d6 100644
--- a/projects/plugins/boost/app/assets/src/js/utils/generate-critical-css.ts
+++ b/projects/plugins/boost/app/assets/src/js/utils/generate-critical-css.ts
@@ -76,12 +76,12 @@ export default async function generateCriticalCss(
hasGenerateRun = true;
let cancelling = false;
- if ( reset ) {
- await clearDismissedRecommendations();
- updateGenerateStatus( true, 0 );
- }
-
try {
+ if ( reset ) {
+ await clearDismissedRecommendations();
+ updateGenerateStatus( true, 0 );
+ }
+
// Fetch a list of provider keys and URLs while loading the Critical CSS lib.
const cssStatus = await requestGeneration( reset, isShowstopperRetry );
diff --git a/projects/plugins/boost/app/class-jetpack-boost.php b/projects/plugins/boost/app/class-jetpack-boost.php
index cbef9b8fcd3f3..02ac717a4041c 100644
--- a/projects/plugins/boost/app/class-jetpack-boost.php
+++ b/projects/plugins/boost/app/class-jetpack-boost.php
@@ -12,19 +12,17 @@
namespace Automattic\Jetpack_Boost;
-use Automattic\Jetpack\Config as Jetpack_Config;
use Automattic\Jetpack_Boost\Admin\Admin;
+use Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS\Critical_CSS;
+use Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS\Critical_CSS_Storage;
+use Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS\Regenerate_Admin_Notice;
+use Automattic\Jetpack_Boost\Features\Optimizations\Optimizations;
use Automattic\Jetpack_Boost\Lib\Analytics;
use Automattic\Jetpack_Boost\Lib\CLI;
-use Automattic\Jetpack_Boost\Lib\Config;
use Automattic\Jetpack_Boost\Lib\Connection;
-use Automattic\Jetpack_Boost\Lib\Speed_Score_History;
-use Automattic\Jetpack_Boost\Lib\Viewport;
-use Automattic\Jetpack_Boost\Modules\Critical_CSS\Critical_CSS;
-use Automattic\Jetpack_Boost\Modules\Critical_CSS\Regenerate_Admin_Notice;
-use Automattic\Jetpack_Boost\Modules\Lazy_Images\Lazy_Images;
-use Automattic\Jetpack_Boost\Modules\Module;
-use Automattic\Jetpack_Boost\Modules\Render_Blocking_JS\Render_Blocking_JS;
+use Automattic\Jetpack_Boost\Lib\Setup;
+use Automattic\Jetpack_Boost\REST_API\Endpoints\Optimization_Status;
+use Automattic\Jetpack_Boost\REST_API\REST_API;
/**
* The core plugin class.
@@ -40,28 +38,6 @@
*/
class Jetpack_Boost {
- const MODULES = array(
- Critical_CSS::MODULE_SLUG => Critical_CSS::class,
- Lazy_Images::MODULE_SLUG => Lazy_Images::class,
- Render_Blocking_JS::MODULE_SLUG => Render_Blocking_JS::class,
- );
-
- /**
- * Default enabled modules.
- */
- const ENABLED_MODULES_DEFAULT = array();
-
- /**
- * Default available modules.
- */
- const AVAILABLE_MODULES_DEFAULT = array(
- Critical_CSS::MODULE_SLUG,
- Render_Blocking_JS::MODULE_SLUG,
- Lazy_Images::MODULE_SLUG,
- );
-
- const CURRENT_CONFIG_ID = 'default';
-
/**
* The unique identifier of this plugin.
*
@@ -78,21 +54,6 @@ class Jetpack_Boost {
*/
private $version;
- /**
- * The config
- *
- * @since 1.0.0
- * @var Config|null $config The configuration object
- */
- private $config;
-
- /**
- * Store all plugin module instances here
- *
- * @var array
- */
- private $modules = array();
-
/**
* The Jetpack Boost Connection manager instance.
*
@@ -127,20 +88,12 @@ public function __construct() {
\WP_CLI::add_command( 'jetpack-boost', $cli_instance );
}
- // Initialize the config module separately.
- $this->init_config();
-
- $this->prepare_modules();
+ $optimizations = new Optimizations();
+ Setup::add( $optimizations );
// Initialize the Admin experience.
- $this->init_admin();
-
- // Module readiness filter.
- add_action( 'wp_head', array( $this, 'display_meta_field_module_ready' ) );
-
- add_action( 'init', array( $this, 'initialize_modules' ) );
+ $this->init_admin( $optimizations );
add_action( 'init', array( $this, 'init_textdomain' ) );
- add_action( 'init', array( $this, 'register_cache_clear_actions' ) );
add_action( 'handle_theme_change', array( $this, 'handle_theme_change' ) );
@@ -156,307 +109,23 @@ private function register_deactivation_hook() {
register_deactivation_hook( $plugin_file, array( $this, 'deactivate' ) );
}
- /**
- * Wipe all cached values.
- */
- public function clear_cache() {
- do_action( 'jetpack_boost_clear_cache' );
- }
-
/**
* Plugin deactivation handler. Clear cache, and reset admin notices.
*/
public function deactivate() {
do_action( 'jetpack_boost_deactivate' );
-
- $this->clear_cache();
- Admin::clear_dismissed_notices();
- }
-
- /**
- * Plugin uninstallation handler. Delete all settings and cache.
- */
- public function uninstall() {
- do_action( 'jetpack_boost_uninstall' );
-
- Speed_Score_History::clear_all();
- $this->clear_cache();
- delete_option( apply_filters( 'jetpack_boost_options_store_key_name', 'jetpack_boost_config' ) );
- }
-
- /**
- * Handlers for clearing module caches go here, so that caches get cleared even if the module is not enabled.
- */
- public function register_cache_clear_actions() {
- add_action( 'jetpack_boost_clear_cache', array( $this, 'record_clear_cache_event' ) );
- }
-
- /**
- * Record the clear cache event.
- */
- public function record_clear_cache_event() {
+ do_action( 'jetpack_boost_clear_cache' );
Analytics::record_user_event( 'clear_cache' );
- }
-
- /**
- * Initialize modules.
- *
- * Note: this method ignores the nonce verification linter rule, as jb-disable-modules is intended to work
- * without a nonce.
- *
- * phpcs:disable WordPress.Security.NonceVerification.Recommended
- */
- public function prepare_modules() {
- $available_modules = $this->get_available_modules();
-
- $forced_disabled_modules = array();
-
- // Get the lists of modules explicitly disabled from the 'jb-disable-modules' query string.
- // The parameter is a comma separated value list of module slug.
- if ( ! empty( $_GET['jb-disable-modules'] ) ) {
- // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash
- // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $forced_disabled_modules = array_map( 'sanitize_key', explode( ',', $_GET['jb-disable-modules'] ) );
- }
-
- foreach ( self::MODULES as $module_slug => $module_class ) {
- // Don't register modules that have been forcibly disabled from the url 'jb-disable-modules' query string parameter.
- if ( in_array( $module_slug, $forced_disabled_modules, true ) || in_array( 'all', $forced_disabled_modules, true ) ) {
- continue;
- }
-
- // All Jetpack Boost modules should extend Module class.
- if ( ! is_subclass_of( $module_class, Module::class ) ) {
- continue;
- }
-
- // Don't register modules that aren't available.
- if ( ! in_array( $module_slug, $available_modules, true ) ) {
- continue;
- }
-
- $module = new $module_class();
- $this->modules[ $module_slug ] = $module;
- }
-
- do_action( 'jetpack_boost_modules_loaded' );
- }
-
- /**
- * Initialize modules when WordPress is ready
- */
- public function initialize_modules() {
- foreach ( $this->modules as $module_slug => $module ) {
- if ( true === $this->get_module_status( $module_slug ) ) {
- $module->initialize();
- }
- }
- }
-
- /**
- * Returns the list of available modules.
- *
- * @return array The available modules.
- */
- public function get_available_modules() {
- $available_modules = self::AVAILABLE_MODULES_DEFAULT;
-
- // Add the Lazy Images module if Jetpack Lazy Images module is enabled.
- if ( Lazy_Images::is_jetpack_lazy_images_module_enabled() ) {
- $available_modules = array_unique( array_merge( self::AVAILABLE_MODULES_DEFAULT, array( Lazy_Images::MODULE_SLUG ) ) );
- }
-
- return apply_filters(
- 'jetpack_boost_modules',
- $available_modules
- );
- }
-
- /**
- * Returns an array of active modules.
- */
- public function get_active_modules() {
- // Cache active modules.
- static $active_modules = null;
- if ( null !== $active_modules ) {
- return $active_modules;
- }
-
- return array_filter(
- $this->modules,
- function ( $module, $module_slug ) {
- return true === $this->get_module_status( $module_slug );
- },
- ARRAY_FILTER_USE_BOTH
- );
- }
-
- /**
- * Returns the status of a given module.
- *
- * @param string $module_slug The module's slug.
- *
- * @return bool The enablement status of the module.
- */
- public function get_module_status( $module_slug ) {
- $default_module_status = in_array( $module_slug, self::ENABLED_MODULES_DEFAULT, true );
-
- return apply_filters( 'jetpack_boost_module_enabled', $default_module_status, $module_slug );
- }
-
- /**
- * Check if a module is enabled.
- *
- * @param boolean $is_enabled Default value.
- * @param string $module_slug The module we are checking.
- *
- * @return mixed|null
- */
- public function is_module_enabled( $is_enabled, $module_slug ) {
- do_action( 'jetpack_boost_pre_is_module_enabled', $is_enabled, $module_slug );
-
- return $this->config()->get_value( "$module_slug/enabled", $is_enabled );
- }
-
- /**
- * Set status of a module.
- *
- * @param boolean $is_enabled Default value.
- * @param string $module_slug The module we are checking.
- */
- public function set_module_status( $is_enabled, $module_slug ) {
- do_action( 'jetpack_boost_pre_set_module_status', $is_enabled, $module_slug );
- Analytics::record_user_event(
- 'set_module_status',
- array(
- 'module' => $module_slug,
- 'status' => $is_enabled,
- )
- );
- $this->config()->set_value( "$module_slug/enabled", $is_enabled, true );
- }
-
- /**
- * Get critical CSS viewport sizes.
- *
- * @param mixed $default The default value.
- *
- * @return mixed|null
- */
- public function get_critical_css_viewport_sizes( $default ) {
- return $this->config()->get_value( 'critical-css/settings/viewport_sizes', $default );
- }
-
- /**
- * Get critical CSS default viewports.
- *
- * @param mixed $default The default value.
- *
- * @return mixed|null
- */
- public function get_critical_css_default_viewports( $default ) {
- return $this->config()->get_value( 'critical-css/settings/default_viewports', $default );
- }
-
- /**
- * Get critical CSS ignore rules.
- *
- * @param mixed $default The default value.
- *
- * @return mixed|null
- */
- public function get_critical_css_ignore_rules( $default ) {
- return $this->config()->get_value( 'critical-css/settings/css-ignore-rules', $default );
- }
-
- /**
- * Returns configuration array.
- *
- * @return Config Configuration array.
- */
- public function config() {
- if ( ! $this->config ) {
- do_action( 'jetpack_boost_pre_get_config' );
- $this->config = Config::get( self::CURRENT_CONFIG_ID ); // under the hood, this actually fetches from an option, not the config cache.
- }
-
- return apply_filters( 'jetpack_boost_config', $this->config );
- }
-
- /**
- * Initialize config system.
- *
- * @todo This should be replaced by a proper configuration implementation eventually.
- */
- public function init_config() {
- add_action( 'switch_blog', array( $this, 'clear_memoized_config' ) );
- add_filter( 'jetpack_boost_module_enabled', array( $this, 'is_module_enabled' ), 0, 2 );
- add_filter( 'jetpack_boost_critical_css_viewport_sizes', array( $this, 'get_critical_css_viewport_sizes' ) );
- add_filter( 'jetpack_boost_critical_css_default_viewports', array( $this, 'get_critical_css_default_viewports' ) );
- add_filter( 'jetpack_boost_critical_css_ignore_rules', array( $this, 'get_critical_css_ignore_rules' ) );
- }
-
- /**
- * Clear the memoized config, executed on `switch_blog`
- */
- public function clear_memoized_config() {
- $this->config = null;
- }
-
- /**
- * Returns a default config array.
- *
- * @return array Default config.
- */
- public static function get_default_config_array() {
- return apply_filters(
- 'jetpack_boost_config_array',
- array(
- Render_Blocking_JS::MODULE_SLUG => array(
- 'enabled' => false,
- ),
- Critical_CSS::MODULE_SLUG => array(
- 'enabled' => false,
- 'settings' => array(
- 'viewport_sizes' => Viewport::DEFAULT_VIEWPORT_SIZES,
- 'default_viewports' => Viewport::DEFAULT_VIEWPORTS,
- 'css-ignore-rules' => array(
- // TODO: Define if we need any default CSS ignore rules
- // Example regex, exclude all css where there is a url inside.
- 'url\(',
- ),
- ),
- ),
- Lazy_Images::MODULE_SLUG => array(
- 'enabled' => false,
- ),
- 'show_rating_prompt' => true,
- )
- );
+ Admin::clear_dismissed_notices();
}
/**
* Initialize the admin experience.
*/
- public function init_admin() {
- if ( ! apply_filters( 'jetpack_boost_connection_bypass', false ) ) {
- $jetpack_config = new Jetpack_Config();
- $jetpack_config->ensure(
- 'connection',
- array(
- 'slug' => 'jetpack-boost',
- 'name' => 'Jetpack Boost',
- 'url_info' => '', // Optional, URL of the plugin.
- )
- );
- }
-
- /**
- * The class responsible for defining all actions that occur in the admin area.
- */
- require_once plugin_dir_path( __FILE__ ) . 'admin/class-admin.php';
-
- new Admin( $this );
+ public function init_admin( $modules ) {
+ REST_API::register( Optimization_Status::class );
+ $this->connection->ensure_connection();
+ new Admin( $modules );
}
/**
@@ -470,15 +139,6 @@ public function init_textdomain() {
);
}
- /**
- * Registers the `jetpack_boost_url_ready` filter which allows modules to provide their readiness status.
- */
- public function display_meta_field_module_ready() {
- ?>
-
- version;
}
- /**
- * Returns a list of admin notices to show. Asks each module to provide admin notices the user needs to see.
- *
- * @return \Automattic\Jetpack_Boost\Admin\Admin_Notice[]
- */
- public function get_admin_notices() {
- $all_notices = array();
-
- foreach ( $this->get_active_modules() as $module ) {
- $module_notices = $module->get_admin_notices();
-
- if ( ! empty( $module_notices ) ) {
- $all_notices = array_merge( $all_notices, $module_notices );
- }
- }
-
- return $all_notices;
- }
-
/**
* Handle an environment change to set the correct status to the Critical CSS request.
* This is done here so even if the Critical CSS module is switched off we can
@@ -528,4 +169,28 @@ public function handle_theme_change() {
Admin::clear_dismissed_notice( Regenerate_Admin_Notice::SLUG );
\update_option( Critical_CSS::RESET_REASON_STORAGE_KEY, Regenerate_Admin_Notice::REASON_THEME_CHANGE, false );
}
+
+ /**
+ * Plugin uninstallation handler. Delete all settings and cache.
+ */
+ public function uninstall() {
+
+ global $wpdb;
+
+ // When uninstalling, make sure all deactivation cleanups have run as well.
+ $this->deactivate();
+
+ // Delete all Jetpack Boost options.
+ $wpdb->query(
+ "
+ DELETE
+ FROM `$wpdb->options`
+ WHERE `option_name` LIKE jetpack_boost_%
+ "
+ );
+
+ // Delete stored Critical CSS.
+ ( new Critical_CSS_Storage() )->clear();
+
+ }
}
diff --git a/projects/plugins/boost/app/contracts/Feature.php b/projects/plugins/boost/app/contracts/Feature.php
new file mode 100644
index 0000000000000..33edf2c86b622
--- /dev/null
+++ b/projects/plugins/boost/app/contracts/Feature.php
@@ -0,0 +1,11 @@
+feature = $feature;
+ $this->status = new Status( $feature->get_slug() );
+ }
+}
diff --git a/projects/plugins/boost/app/features/optimizations/Optimizations.php b/projects/plugins/boost/app/features/optimizations/Optimizations.php
new file mode 100644
index 0000000000000..a933dbeb54edd
--- /dev/null
+++ b/projects/plugins/boost/app/features/optimizations/Optimizations.php
@@ -0,0 +1,127 @@
+get_slug();
+ $this->features[ $slug ] = new Optimization( $feature );
+ }
+ }
+
+ public function available_modules() {
+ $forced_disabled_modules = $this->get_disabled_modules();
+
+ if ( empty( $forced_disabled_modules ) ) {
+ return $this->features;
+ }
+
+ if ( array( 'all' ) === $forced_disabled_modules ) {
+ return array();
+ }
+
+ $available_modules = array();
+ foreach ( $this->features as $slug => $feature ) {
+ if ( ! in_array( $slug, $forced_disabled_modules, true ) ) {
+ $available_modules[ $slug ] = $feature;
+ }
+ }
+
+ return $available_modules;
+ }
+
+ public function have_enabled_modules() {
+ return count( $this->get_status() ) > 0;
+ }
+
+ public function get_status() {
+ $status = array();
+ foreach ( $this->features as $slug => $optimization ) {
+ $status[ $slug ] = $optimization->status->is_enabled();
+ }
+ return $status;
+ }
+
+ public function register_endpoints( $feature ) {
+ if ( ! $feature instanceof Has_Endpoints ) {
+ return false;
+ }
+
+ if ( empty( $feature->get_endpoints() ) ) {
+ return false;
+ }
+
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setup() {
+
+ foreach ( $this->available_modules() as $slug => $optimization ) {
+
+ if ( ! $optimization->status->is_enabled() ) {
+ continue;
+ }
+
+ $optimization->feature->setup();
+ $this->register_endpoints( $optimization->feature );
+
+ do_action( "jetpack_boost_{$slug}_initialized", $this );
+
+ }
+ }
+
+ /**
+ * Get the lists of modules explicitly disabled from the 'jb-disable-modules' query string.
+ * The parameter is a comma separated value list of module slug.
+ *
+ * @return array
+ */
+
+ public function get_disabled_modules() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ if ( ! empty( $_GET['jb-disable-modules'] ) ) {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ return array_map( 'sanitize_key', explode( ',', $_GET['jb-disable-modules'] ) );
+ }
+
+ return array();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setup_trigger() {
+ return 'plugins_loaded';
+ }
+
+}
diff --git a/projects/plugins/boost/app/modules/critical-css/class-admin-bar-css-compat.php b/projects/plugins/boost/app/features/optimizations/critical-css/Admin_Bar_Compatibilty.php
similarity index 75%
rename from projects/plugins/boost/app/modules/critical-css/class-admin-bar-css-compat.php
rename to projects/plugins/boost/app/features/optimizations/critical-css/Admin_Bar_Compatibilty.php
index 5d7924ac6bf13..a2f18f83e04c0 100644
--- a/projects/plugins/boost/app/modules/critical-css/class-admin-bar-css-compat.php
+++ b/projects/plugins/boost/app/features/optimizations/critical-css/Admin_Bar_Compatibilty.php
@@ -1,24 +1,11 @@
storage = new Critical_CSS_Storage();
+ $this->paths = new Source_Providers();
+
+ }
+
+ /**
+ * This is only run if Critical CSS module has been activated.
+ */
+ public function setup() {
+ // Touch to setup the post type. This is a temporary hack.
+ // This should instantiate a new Post_Type_Storage class,
+ // so that Critical_CSS class is responsible
+ // for setting up the storage.
+ $recommendations = new Recommendations();
+ $recommendations->attach_hooks();
+
+ add_action( 'wp', array( $this, 'display_critical_css' ) );
+
+ if ( Generator::is_generating_critical_css() ) {
+ add_action( 'wp_head', array( $this, 'display_generate_meta' ), 0 );
+ $this->force_logged_out_render();
+ }
+
+ add_action( 'handle_theme_change', array( $this, 'clear_critical_css' ) );
+ add_action( 'jetpack_boost_clear_cache', array( $this, 'clear_critical_css' ) );
+ add_filter( 'jetpack_boost_js_constants', array( $this, 'add_critical_css_constants' ) );
+
+ REST_API::register( $this->get_endpoints() );
+ return true;
+ }
+
+ public function get_slug() {
+ return 'critical-css';
+ }
+
+ /**
+ * Renders a tag used to verify this is a valid page to generate Critical CSS with.
+ */
+ public function display_generate_meta() {
+ ?>
+
+ paths->get_current_request_css();
+ if ( ! $critical_css ) {
+ return;
+ }
+
+ $display = new Display_Critical_CSS( $critical_css );
+ add_action( 'wp_head', array( $display, 'display_critical_css' ), 0 );
+ add_filter( 'style_loader_tag', array( $display, 'asynchronize_stylesheets' ), 10, 4 );
+ add_action( 'wp_footer', array( $display, 'onload_flip_stylesheets' ) );
+ }
+
+ /**
+ * Clear Critical CSS.
+ */
+ public function clear_critical_css() {
+ // Mass invalidate all cached values.
+ // ^^ Not true anymore. Mass invalidate __some__ cached values.
+ $this->storage->clear();
+ Critical_CSS_State::reset();
+ }
+
+ /**
+ * Force the current page to render as viewed by a logged out user. Useful when generating
+ * Critical CSS.
+ */
+ private function force_logged_out_render() {
+ $current_user_id = get_current_user_id();
+
+ if ( 0 !== $current_user_id ) {
+ // Force current user to 0 to ensure page is rendered as a non-logged-in user.
+ wp_set_current_user( 0 );
+
+ // Turn off display of admin bar.
+ add_filter( 'show_admin_bar', '__return_false', PHP_INT_MAX );
+ }
+ }
+
+ /**
+ * Override; returns an admin notice to show if there was a reset reason.
+ *
+ * @TODO:
+ * There should be an Admin_Notice class
+ * To create a notice, (new Admin_Notice())->create("notice text");
+ * To view notices: (new Admin_Notice())->get_all();
+ * @return null|\Automattic\Jetpack_Boost\Admin\Admin_Notice[]
+ */
+ public function get_admin_notices() {
+ $reason = \get_option( self::RESET_REASON_STORAGE_KEY );
+
+ if ( ! $reason ) {
+ return array();
+ }
+
+ return array( new Regenerate_Admin_Notice( $reason ) );
+ }
+
+ /**
+ * Clear Critical CSS reset reason option.
+ *
+ * @TODO: Admin notices need to be moved elsewhere.
+ * Note: Looks like we need a way to and options throughout the app.
+ * This is why it's currently awkwardly using a static method with a constant
+ * If we could trust classes to use constructors properly - without performing actions
+ * Then we could easily (and cheaply) instantiate all Boost objects
+ * and kindly ask them to delete themselves
+ */
+ public static function clear_reset_reason() {
+ \delete_option( self::RESET_REASON_STORAGE_KEY );
+ }
+
+ /**
+ * Add Critical CSS related constants to be passed to JavaScript only if the module is enabled.
+ *
+ * @param array $constants Constants to be passed to JavaScript.
+ *
+ * @return array
+ */
+ public function add_critical_css_constants( $constants ) {
+ // Information about the current status of Critical CSS / generation.
+ $generator = new Generator();
+ $constants['criticalCssStatus'] = $generator->get_local_critical_css_generation_info();
+
+ return $constants;
+ }
+
+ /**
+ * @TODO: Facepalm. PHP Typehinting is broken.
+ * @return Endpoint[]
+ *
+ */
+ public function get_endpoints() {
+ return array(
+ Generator_Status::class,
+ Generator_Request::class,
+ Generator_Success::class,
+ Recommendations_Dismiss::class,
+ Recommendations_Reset::class,
+ Generator_Error::class,
+ );
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function setup_trigger() {
+ return 'init';
+ }
+}
diff --git a/projects/plugins/boost/app/modules/critical-css/class-critical-css-state.php b/projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_State.php
similarity index 97%
rename from projects/plugins/boost/app/modules/critical-css/class-critical-css-state.php
rename to projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_State.php
index 1768bd0227abc..e5867d9887da1 100644
--- a/projects/plugins/boost/app/modules/critical-css/class-critical-css-state.php
+++ b/projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_State.php
@@ -7,10 +7,9 @@
* @package automattic/jetpack-boost
*/
-namespace Automattic\Jetpack_Boost\Modules\Critical_CSS;
+namespace Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS;
use Automattic\Jetpack_Boost\Lib\Transient;
-use Automattic\Jetpack_Boost\Modules\Critical_CSS\Providers\Provider;
/**
* Critical CSS State
@@ -203,11 +202,6 @@ public function get_core_providers_status( $keys ) {
protected function get_provider_sources( $providers ) {
$sources = array();
- /**
- * Provider.
- *
- * @var $provider Provider
- */
foreach ( $providers as $provider ) {
$provider_name = $provider::get_provider_name();
@@ -382,7 +376,7 @@ public function get_percent_complete() {
/**
* Reset the Critical CSS state.
*/
- public function reset() {
+ public static function reset() {
Transient::delete( self::KEY );
}
diff --git a/projects/plugins/boost/app/modules/critical-css/class-critical-css-storage.php b/projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_Storage.php
similarity index 94%
rename from projects/plugins/boost/app/modules/critical-css/class-critical-css-storage.php
rename to projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_Storage.php
index 29f233f445fe5..820b560ac3de3 100644
--- a/projects/plugins/boost/app/modules/critical-css/class-critical-css-storage.php
+++ b/projects/plugins/boost/app/features/optimizations/critical-css/Critical_CSS_Storage.php
@@ -7,7 +7,7 @@
* @package automattic/jetpack-boost
*/
-namespace Automattic\Jetpack_Boost\Modules\Critical_CSS;
+namespace Automattic\Jetpack_Boost\Features\Optimizations\Critical_CSS;
use Automattic\Jetpack_Boost\Lib\Storage_Post_Type;
diff --git a/projects/plugins/boost/app/features/optimizations/critical-css/Display_Critical_CSS.php b/projects/plugins/boost/app/features/optimizations/critical-css/Display_Critical_CSS.php
new file mode 100644
index 0000000000000..35cf33817306c
--- /dev/null
+++ b/projects/plugins/boost/app/features/optimizations/critical-css/Display_Critical_CSS.php
@@ -0,0 +1,149 @@
+css = $css;
+ }
+
+ /**
+ * Converts existing screen CSS to be asynchronously loaded.
+ *
+ * @param string $html The link tag for the enqueued style.
+ * @param string $handle The style's registered handle.
+ * @param string $href The stylesheet's source URL.
+ * @param string $media The stylesheet's media attribute.
+ *
+ * @return string
+ * @see style_loader_tag
+ */
+ public function asynchronize_stylesheets(
+ $html,
+ $handle,
+ $href,
+ $media
+ ) {
+ // If there is no critical CSS, do not alter the stylesheet loading.
+ if ( false === $this->css ) {
+ return $html;
+ }
+
+ $available_methods = array(
+ 'async' => 'media="not all" data-media="' . $media . '" onload="this.media=this.dataset.media; delete this.dataset.media; this.removeAttribute( \'onload\' );"',
+ 'deferred' => 'media="not all" data-media="' . $media . '"',
+ );
+
+ /**
+ * Loading method for stylesheets.
+ *
+ * Filter the loading method for each stylesheet for the screen with following values:
+ * async - Stylesheets are loaded asynchronously.
+ * Styles are applied once the stylesheet is loaded completely without render blocking.
+ * deferred - Loading of stylesheets are deferred until the window load event.
+ * Styles from all the stylesheets are applied at once after the page load.
+ *
+ * Stylesheet loading behaviour is not altered for any other value such as false or 'default'.
+ * Stylesheet loading is instant and the process blocks the page rendering.
+ * Eg: add_filter( 'jetpack_boost_async_style', '__return_false' );
+ *
+ * @param string $handle The style's registered handle.
+ * @param string $media The stylesheet's media attribute.
+ *
+ * @see onload_flip_stylesheets for how stylesheets loading is deferred.
+ *
+ * @todo Retrieve settings from database, either via auto-configuration or UI option.
+ */
+ $method = apply_filters( 'jetpack_boost_async_style', 'async', $handle, $media );
+
+ // If the loading method is not allowed, do not alter the stylesheet loading.
+ if ( ! isset( $available_methods[ $method ] ) ) {
+ return $html;
+ }
+
+ $html_no_script = '' . $html . ' ';
+
+ // Update the stylesheet markup for allowed methods.
+ $html = preg_replace( '~media=(\'[^\']+\')|("[^"]+")~', $available_methods[ $method ], $html );
+
+ // Append to the HTML stylesheet tag the same untouched HTML stylesheet tag within the noscript tag
+ // to support the rendering of the stylesheet when JavaScript is disabled.
+ return $html_no_script . $html;
+ }
+
+ /**
+ * Prints the critical CSS to the page.
+ */
+ public function display_critical_css() {
+ $critical_css = $this->css;
+
+ if ( false === $critical_css ) {
+ return false;
+ }
+
+ echo ' tag (or any HTML tags) in output.
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo wp_strip_all_tags( $critical_css );
+
+ echo '';
+ }
+
+ /**
+ * Add a small piece of JavaScript to the footer, which on load flips all
+ * linked stylesheets from media="not all" to "all", and switches the
+ * Critical CSS tag (or any HTML tags) in output.
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo wp_strip_all_tags( $critical_css );
-
- echo '';
- }
-
- /**
- * Check if the current URL is warmed up. For this module, "warmed up" means that
- * either Critical CSS has been generated for this page, or this page is not
- * eligible to have Critical CSS generated for it.
- *
- * @param bool $ready Injected filter value.
- *
- * @return bool
- */
- public function is_ready_filter( $ready ) {
- if ( ! $ready ) {
- return $ready;
- }
-
- // If this page has no provider keys, it is ineligible for Critical CSS.
- $keys = $this->get_current_request_css_keys();
- if ( count( $keys ) === 0 ) {
- return true;
- }
-
- // Return "ready" if Critical CSS has been generated.
- return ! empty( $this->get_critical_css() );
- }
-
- /**
- * Force the current page to render as viewed by a logged out user. Useful when generating
- * Critical CSS.
- */
- private function force_logged_out_render() {
- $current_user_id = get_current_user_id();
-
- if ( 0 !== $current_user_id ) {
- // Force current user to 0 to ensure page is rendered as a non-logged-in user.
- wp_set_current_user( 0 );
-
- // Turn off display of admin bar.
- add_filter( 'show_admin_bar', '__return_false', PHP_INT_MAX );
- }
- }
-
- /**
- * AJAX handler to handle proxying of external CSS resources.
- */
- public function handle_css_proxy() {
- // Verify valid nonce.
- if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['nonce'] ), self::GENERATE_PROXY_NONCE ) ) {
- wp_die( '', 400 );
- }
-
- // Make sure currently logged in as admin.
- if ( ! $this->current_user_can_modify_critical_css() ) {
- wp_die( '', 400 );
- }
-
- // Reject any request made when not generating.
- if ( ! $this->state->is_pending() ) {
- wp_die( '', 400 );
- }
-
- // Validate URL and fetch.
- $proxy_url = filter_var( wp_unslash( $_POST['proxy_url'] ), FILTER_VALIDATE_URL );
- if ( ! wp_http_validate_url( $proxy_url ) ) {
- die( 'Invalid URL' );
- }
-
- $response = wp_remote_get( $proxy_url );
- if ( is_wp_error( $response ) ) {
- // TODO: Nicer error handling.
- die( 'error' );
- }
-
- header( 'Content-type: text/css' );
-
- // Outputting proxied CSS contents unescaped.
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo wp_strip_all_tags( $response['body'] );
-
- die();
- }
-
- /**
- * API helper for ensuring this module is enabled before allowing an API
- * endpoint to continue. Will die if this module is not initialized, with
- * a status message indicating so.
- */
- public function ensure_module_initialized() {
- if ( ! $this->is_initialized() ) {
- wp_send_json( array( 'status' => 'module-unavailable' ) );
- }
- }
-
- /**
- * Add a small piece of JavaScript to the footer, which on load flips all
- * linked stylesheets from media="not all" to "all", and switches the
- * Critical CSS