diff --git a/.github/workflows/update-phan-stubs.yml b/.github/workflows/update-phan-stubs.yml
index 46c2230c4ce2b..944b9e14f9523 100644
--- a/.github/workflows/update-phan-stubs.yml
+++ b/.github/workflows/update-phan-stubs.yml
@@ -63,7 +63,7 @@ jobs:
git checkout -b update/phan-custom-stubs
git commit -am 'phan: Update custom stubs'
git push origin HEAD
- gh pr create --title 'phan: Update custom stubs' --body 'This is an automatic update generated by a GitHub Action. If closed it will be recreated the next time the action runs.' --label '[Pri] Normal' --label '[Type] Janitorial' --label '[Status] Needs Review'
+ gh pr create --title 'phan: Update custom stubs' --body 'This is an automatic update generated by a GitHub Action. If closed it will be recreated the next time the action runs.' --label '[Pri] Normal' --label '[Type] Janitorial' --label '[Status] Needs Review' --reviewer Automattic/jetpack-garage
- name: Update existing branch
if: steps.changes.outputs.needed == 'true' && steps.changes.outputs.has-branch == 'true'
diff --git a/.phan/stubs/akismet-stubs.php b/.phan/stubs/akismet-stubs.php
index 74b8062fe05be..0ce1519bcf851 100644
--- a/.phan/stubs/akismet-stubs.php
+++ b/.phan/stubs/akismet-stubs.php
@@ -1,6 +1,6 @@
a {
+ position: relative;
+ top: -3px;
+ margin-left: 0;
+ vertical-align: baseline;
+ }
+}
diff --git a/projects/packages/external-media/src/features/admin/external-media-import.js b/projects/packages/external-media/src/features/admin/external-media-import.js
index d6feba02f7716..f1abfe45f3722 100644
--- a/projects/packages/external-media/src/features/admin/external-media-import.js
+++ b/projects/packages/external-media/src/features/admin/external-media-import.js
@@ -1,3 +1,4 @@
+import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import { sprintf, __ } from '@wordpress/i18n';
import { useState, useEffect } from 'react';
import { createPortal } from 'react-dom';
@@ -22,6 +23,7 @@ const Notice = ( { message, onDismiss } ) => (
const JetpackExternalMediaImport = () => {
const [ selectedSource, setSelectedSource ] = useState( null );
const [ noticeMessage, setNoticeMessage ] = useState( '' );
+ const { tracks } = useAnalytics();
const ExternalLibrary = getExternalLibrary( selectedSource );
const selectButtonText = ( selectedImages, isCopying ) => {
@@ -77,6 +79,9 @@ const JetpackExternalMediaImport = () => {
const slug = event.target.dataset.slug;
if ( slug ) {
setSelectedSource( slug );
+ tracks.recordEvent( 'jetpack_external_media_import_media_page_import_click', {
+ media_source: slug,
+ } );
}
};
@@ -89,7 +94,7 @@ const JetpackExternalMediaImport = () => {
element.removeEventListener( 'click', handleClick );
}
};
- }, [] );
+ }, [ tracks ] );
return (
<>
diff --git a/projects/packages/external-media/src/features/admin/external-media-import.php b/projects/packages/external-media/src/features/admin/external-media-import.php
index c5a43769b7f09..972f8b7b9c764 100644
--- a/projects/packages/external-media/src/features/admin/external-media-import.php
+++ b/projects/packages/external-media/src/features/admin/external-media-import.php
@@ -47,10 +47,39 @@ function add_jetpack_external_media_import_page() {
__NAMESPACE__ . '\render_jetpack_external_media_import_page'
);
+ add_action( 'load-upload.php', __NAMESPACE__ . '\enqueue_jetpack_external_media_import_button' );
add_action( "load-$external_media_import_page_hook", __NAMESPACE__ . '\enqueue_jetpack_external_media_import_page' );
}
add_action( 'admin_menu', __NAMESPACE__ . '\add_jetpack_external_media_import_page' );
+/**
+ * Enqueue the assets of the Jetpack external media import button.
+ */
+function enqueue_jetpack_external_media_import_button() {
+ $assets_base_path = 'build/';
+ $asset_name = 'jetpack-external-media-import-button';
+
+ Assets::register_script(
+ $asset_name,
+ $assets_base_path . "$asset_name/$asset_name.js",
+ External_Media::BASE_FILE,
+ array(
+ 'in_footer' => true,
+ 'textdomain' => 'jetpack-external-media',
+ 'css_path' => $assets_base_path . "$asset_name/$asset_name.css",
+ )
+ );
+
+ Assets::enqueue_script( $asset_name );
+ wp_localize_script(
+ $asset_name,
+ 'JETPACK_EXTERNAL_MEDIA_IMPORT_BUTTON',
+ array(
+ 'href' => admin_url( 'upload.php?page=jetpack_external_media_import_page&untangling-media=true' ),
+ )
+ );
+}
+
/**
* Enqueue the assets of the Jetpack external media page.
*/
diff --git a/projects/packages/external-media/src/shared/media-browser/index.js b/projects/packages/external-media/src/shared/media-browser/index.js
index e9bd6bd4551aa..7ba3619044401 100644
--- a/projects/packages/external-media/src/shared/media-browser/index.js
+++ b/projects/packages/external-media/src/shared/media-browser/index.js
@@ -1,9 +1,12 @@
-import { Button, Spinner, Composite } from '@wordpress/components';
+import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
+import { Spinner, Composite } from '@wordpress/components';
import { useCallback, useState, useRef, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import React from 'react';
+import MediaBrowserSelectButton from './media-browser-select-button';
import MediaItem from './media-item';
+import usePageSource from './use-page-source';
import './style.scss';
const MAX_SELECTED = 10;
@@ -13,6 +16,7 @@ const MAX_SELECTED = 10;
*
* @param {object} props - The component props
* @param {object[]} props.media - The list of media
+ * @param {string} props.mediaSource - The source of media
* @param {boolean} props.isCopying - Whether the media browser is copying the media
* @param {boolean} props.isLoading - Whether the media browser is loading
* @param {boolean} props.imageOnly - Whether to skip non-media items
@@ -22,12 +26,13 @@ const MAX_SELECTED = 10;
* @param {Function} props.setPath - To set the path for the folder item
* @param {Function} props.nextPage - To get the next path
* @param {Function} props.onCopy - To handle the copy
- * @param {string} props.selectButtonText - The text of the selection button
+ * @param {Function} props.selectButtonText - To get the select button text
* @param {boolean} props.shouldProxyImg - Whether to use the proxy for the media URL
* @return {React.ReactElement} - JSX element
*/
function MediaBrowser( {
media,
+ mediaSource,
isCopying,
isLoading,
imageOnly,
@@ -42,6 +47,8 @@ function MediaBrowser( {
} ) {
const [ selected, setSelected ] = useState( [] );
const gridEl = useRef( null );
+ const { tracks } = useAnalytics();
+ const pageSource = usePageSource();
const select = useCallback(
newlySelected => {
@@ -65,45 +72,29 @@ function MediaBrowser( {
);
const onCopyAndInsert = useCallback( () => {
+ tracks.recordEvent( 'jetpack_external_media_modal_submit', {
+ page: pageSource,
+ media_source: mediaSource,
+ media_count: selected.length,
+ multiple: !! multiple,
+ } );
+
onCopy( selected );
- }, [ selected, onCopy ] );
+ }, [ tracks, pageSource, mediaSource, selected, multiple, onCopy ] );
const hasMediaItems = media.filter( item => item.type !== 'folder' ).length > 0;
- const classes = clsx( {
- 'jetpack-external-media-browser__media': true,
- 'jetpack-external-media-browser__media__loading': isLoading,
- } );
- const wrapper = clsx( {
- 'jetpack-external-media-browser': true,
- [ className ]: true,
- } );
-
- // Using _event to avoid eslint errors. Can change to event if it's in use again.
- const handleMediaItemClick = ( _event, { item } ) => {
- select( item );
- };
- const SelectButton = selectProps => {
- const disabled = selected.length === 0 || isCopying;
+ const getSelectButtonLabel = () => {
const defaultLabel = isCopying
? __( 'Inserting…', 'jetpack-external-media' )
: __( 'Select', 'jetpack-external-media', /* dummy arg to avoid bad minification */ 0 );
- const label = selectProps?.labelText
- ? selectProps?.labelText( selected.length, isCopying )
- : defaultLabel;
-
- return (
-
-
-
- );
+
+ return selectButtonText ? selectButtonText( selected.length, isCopying ) : defaultLabel;
+ };
+
+ // Using _event to avoid eslint errors. Can change to event if it's in use again.
+ const handleMediaItemClick = ( _event, { item } ) => {
+ select( item );
};
// Infinite scroll
@@ -126,11 +117,19 @@ function MediaBrowser( {
}, [ pageHandle, isLoading, gridEl ] ); // eslint-disable-line react-hooks/exhaustive-deps
return (
-
+
}
>
@@ -161,7 +160,14 @@ function MediaBrowser( {
) }
- { hasMediaItems &&
}
+ { hasMediaItems && (
+
+ ) }
);
}
diff --git a/projects/packages/external-media/src/shared/media-browser/media-browser-select-button.js b/projects/packages/external-media/src/shared/media-browser/media-browser-select-button.js
new file mode 100644
index 0000000000000..a612a7daef41a
--- /dev/null
+++ b/projects/packages/external-media/src/shared/media-browser/media-browser-select-button.js
@@ -0,0 +1,24 @@
+import { Button } from '@wordpress/components';
+import React from 'react';
+
+/**
+ * MediaBrowserSelectButton component
+ *
+ * @param {object} props - The component props
+ * @param {string} props.label - The label of the button
+ * @param {boolean} props.isLoading - Whether the button is loading
+ * @param {boolean} props.disabled - Whether the button is disabled
+ * @param {Function} props.onClick - To handle the click
+ * @return {React.ReactElement} - JSX element
+ */
+const MediaBrowserSelectButton = ( { label, isLoading, disabled, onClick } ) => {
+ return (
+
+
+
+ );
+};
+
+export default MediaBrowserSelectButton;
diff --git a/projects/packages/external-media/src/shared/media-browser/use-page-source.js b/projects/packages/external-media/src/shared/media-browser/use-page-source.js
new file mode 100644
index 0000000000000..70cfa13b6e7e6
--- /dev/null
+++ b/projects/packages/external-media/src/shared/media-browser/use-page-source.js
@@ -0,0 +1,12 @@
+import { useSelect } from '@wordpress/data';
+
+const usePageSource = () => {
+ const isEditor = useSelect( select => !! select( 'core/editor' ), [] );
+
+ if ( isEditor ) {
+ return 'editor';
+ }
+ return 'media-library';
+};
+
+export default usePageSource;
diff --git a/projects/packages/external-media/src/shared/sources/google-photos/google-photos-media.js b/projects/packages/external-media/src/shared/sources/google-photos/google-photos-media.js
index e334c03a156e7..5fcb598812966 100644
--- a/projects/packages/external-media/src/shared/sources/google-photos/google-photos-media.js
+++ b/projects/packages/external-media/src/shared/sources/google-photos/google-photos-media.js
@@ -11,6 +11,7 @@ import {
DATE_RANGE_ANY,
} from '../../constants';
import MediaBrowser from '../../media-browser';
+import { MediaSource } from '../../media-service/types';
import { getExternalMediaApiUrl } from '../api';
import Breadcrumbs from './breadcrumbs';
import GoogleFilterOption from './filter-option';
@@ -183,6 +184,7 @@ function GooglePhotosMedia( props ) {
className="jetpack-external-media-browser__google"
key={ listUrl }
media={ media }
+ mediaSource={ MediaSource.GooglePhotos }
imageOnly={ imageOnly }
isCopying={ isCopying }
isLoading={ isLoading }
diff --git a/projects/packages/external-media/src/shared/sources/jetpack-app-media/index.js b/projects/packages/external-media/src/shared/sources/jetpack-app-media/index.js
index a4a2cd0643639..640b38de3781b 100644
--- a/projects/packages/external-media/src/shared/sources/jetpack-app-media/index.js
+++ b/projects/packages/external-media/src/shared/sources/jetpack-app-media/index.js
@@ -136,6 +136,7 @@ function JetpackAppMedia( props ) {
key={ 'jetpack-app-media' }
className="jetpack-external-media-browser__jetpack_app_media_browser"
media={ media }
+ mediaSource={ MediaSource.JetpackAppMedia }
isCopying={ isCopying }
isLoading={ false }
nextPage={ getNextPage }
diff --git a/projects/packages/external-media/src/shared/sources/openverse/index.js b/projects/packages/external-media/src/shared/sources/openverse/index.js
index 331c648b817e3..86675f7cc59b0 100644
--- a/projects/packages/external-media/src/shared/sources/openverse/index.js
+++ b/projects/packages/external-media/src/shared/sources/openverse/index.js
@@ -67,6 +67,7 @@ function OpenverseMedia( props ) {
getNextPage( searchQuery ) }
diff --git a/projects/packages/external-media/src/shared/sources/pexels/index.js b/projects/packages/external-media/src/shared/sources/pexels/index.js
index 83b142ed04fcf..23c162874afe5 100644
--- a/projects/packages/external-media/src/shared/sources/pexels/index.js
+++ b/projects/packages/external-media/src/shared/sources/pexels/index.js
@@ -68,6 +68,7 @@ function PexelsMedia( props ) {
getNextPage( searchQuery ) }
diff --git a/projects/packages/external-media/webpack.config.js b/projects/packages/external-media/webpack.config.js
index abfb18bdd1654..992136af6494e 100644
--- a/projects/packages/external-media/webpack.config.js
+++ b/projects/packages/external-media/webpack.config.js
@@ -5,6 +5,10 @@ module.exports = [
{
entry: {
'jetpack-external-media-editor': './src/features/editor/index.js',
+ 'jetpack-external-media-import-button': [
+ './src/features/admin/external-media-import-button.js',
+ './src/features/admin/external-media-import-button.scss',
+ ],
'jetpack-external-media-import-page': './src/features/admin/external-media-import.js',
},
mode: jetpackWebpackConfig.mode,
diff --git a/projects/packages/forms/changelog/fix-25025-form-seperator b/projects/packages/forms/changelog/fix-25025-form-seperator
new file mode 100644
index 0000000000000..6c872c241915f
--- /dev/null
+++ b/projects/packages/forms/changelog/fix-25025-form-seperator
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Improves the styling options of the separator block when placed inside the form block
diff --git a/projects/packages/forms/changelog/fix-date-validation-bug b/projects/packages/forms/changelog/fix-date-validation-bug
new file mode 100644
index 0000000000000..b812fbbf2ae5f
--- /dev/null
+++ b/projects/packages/forms/changelog/fix-date-validation-bug
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Forms: fixes the date format input if multiple date pickers are used with different date formats.
diff --git a/projects/packages/forms/changelog/fix-form-submit-miulti-page b/projects/packages/forms/changelog/fix-form-submit-miulti-page
new file mode 100644
index 0000000000000..bf6cbe84766ef
--- /dev/null
+++ b/projects/packages/forms/changelog/fix-form-submit-miulti-page
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Forms: Add support for having multiple forms accross paginated pages
diff --git a/projects/packages/forms/changelog/fix-invalid-field-ids b/projects/packages/forms/changelog/fix-invalid-field-ids
new file mode 100644
index 0000000000000..ced045f8f6a66
--- /dev/null
+++ b/projects/packages/forms/changelog/fix-invalid-field-ids
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Forms: Fix invalid html IDs.
diff --git a/projects/packages/forms/src/blocks/contact-form/editor.scss b/projects/packages/forms/src/blocks/contact-form/editor.scss
index d506b5bc8dc98..15b4e982be665 100644
--- a/projects/packages/forms/src/blocks/contact-form/editor.scss
+++ b/projects/packages/forms/src/blocks/contact-form/editor.scss
@@ -93,6 +93,17 @@
&[data-type='jetpack/field-consent'] {
align-self: center;
}
+
+ &:where( .wp-block-jetpack-contact-form .wp-block-separator ){
+ max-width: var( --wp--preset--spacing--80, 100px );
+ margin-left: auto;
+ margin-right: auto;
+ }
+ &:where( .wp-block-jetpack-contact-form .wp-block-separator.is-style-wide ),
+ &:where( .wp-block-jetpack-contact-form .wp-block-separator.is-style-dots ) {
+ max-width: inherit;
+ }
+
}
}
diff --git a/projects/packages/forms/src/class-wpcom-rest-api-v2-endpoint-forms.php b/projects/packages/forms/src/class-wpcom-rest-api-v2-endpoint-forms.php
index ad29686fb12f2..0e9b8295363dd 100644
--- a/projects/packages/forms/src/class-wpcom-rest-api-v2-endpoint-forms.php
+++ b/projects/packages/forms/src/class-wpcom-rest-api-v2-endpoint-forms.php
@@ -159,13 +159,7 @@ public function get_responses( $request ) {
array_diff_key( $filter_args, array( 'post_parent' => '' ) )
);
- $base_fields = array(
- 'email_marketing_consent' => '',
- 'entry_title' => '',
- 'entry_permalink' => '',
- 'feedback_id' => '',
- );
-
+ $base_fields = Contact_Form_Plugin::NON_PRINTABLE_FIELDS;
$data_defaults = array(
'_feedback_author' => '',
'_feedback_author_email' => '',
diff --git a/projects/packages/forms/src/contact-form/class-admin.php b/projects/packages/forms/src/contact-form/class-admin.php
index 0f2ec1379352c..77bb034a45c59 100644
--- a/projects/packages/forms/src/contact-form/class-admin.php
+++ b/projects/packages/forms/src/contact-form/class-admin.php
@@ -702,12 +702,6 @@ public function grunion_manage_post_column_from( $post ) {
* @return void
*/
public function grunion_manage_post_column_response( $post ) {
- $non_printable_keys = array(
- 'email_marketing_consent',
- 'entry_title',
- 'entry_permalink',
- 'feedback_id',
- );
$post_content = get_post_field( 'post_content', $post->ID );
$content = explode( '', $post_content );
@@ -750,7 +744,12 @@ public function grunion_manage_post_column_response( $post ) {
}
}
- $response_fields = array_diff_key( $response_fields, array_flip( $non_printable_keys ) );
+ $url = get_permalink( $post->post_parent );
+ if ( isset( $response_fields['entry_page'] ) ) {
+ $url = add_query_arg( 'page', $response_fields['entry_page'], $url );
+ }
+
+ $response_fields = array_diff_key( $response_fields, array_flip( array_keys( Contact_Form_Plugin::NON_PRINTABLE_FIELDS ) ) );
echo '
';
echo '';
@@ -774,7 +773,7 @@ public function grunion_manage_post_column_response( $post ) {
echo '
' . esc_html( $content_fields['_feedback_ip'] ) . '
';
}
echo '
' . esc_html__( 'Source', 'jetpack-forms' ) . '
';
- echo '
';
+ echo '
';
echo '
';
}
diff --git a/projects/packages/forms/src/contact-form/class-contact-form-field.php b/projects/packages/forms/src/contact-form/class-contact-form-field.php
index 52e5f6385e6e6..4cd4819420d45 100644
--- a/projects/packages/forms/src/contact-form/class-contact-form-field.php
+++ b/projects/packages/forms/src/contact-form/class-contact-form-field.php
@@ -655,7 +655,7 @@ public function render_textarea_field( $id, $label, $value, $class, $required, $
/**
* Return the HTML for the radio field.
*
- * @param int $id - the ID.
+ * @param string $id - the ID (starts with 'g' - see constructor).
* @param string $label - the label.
* @param string $value - the value of the field.
* @param string $class - the field class.
@@ -670,11 +670,20 @@ public function render_radio_field( $id, $label, $value, $class, $required, $req
$field_style = 'style="' . $this->option_styles . '"';
+ $used_html_ids = array();
+
foreach ( (array) $this->get_attribute( 'options' ) as $option_index => $option ) {
$option = Contact_Form_Plugin::strip_tags( $option );
if ( is_string( $option ) && $option !== '' ) {
$radio_value = $this->get_option_value( $this->get_attribute( 'values' ), $option_index, $option );
- $radio_id = "$id-$radio_value";
+ $radio_id = $id . '-' . sanitize_html_class( $radio_value );
+
+ // If exact id was already used in this radio group, append option index.
+ // Multiple 'blue' options would give id-blue, id-blue-1, id-blue-2, etc.
+ if ( isset( $used_html_ids[ $radio_id ] ) ) {
+ $radio_id .= '-' . $option_index;
+ }
+ $used_html_ids[ $radio_id ] = true;
$field .= "";
$field .= "option_styles . '"';
+ $used_html_ids = array();
+
foreach ( (array) $this->get_attribute( 'options' ) as $option_index => $option ) {
$option = Contact_Form_Plugin::strip_tags( $option );
if ( is_string( $option ) && $option !== '' ) {
$checkbox_value = $this->get_option_value( $this->get_attribute( 'values' ), $option_index, $option );
- $checkbox_id = "$id-$checkbox_value";
+ $checkbox_id = $id . '-' . sanitize_html_class( $checkbox_value );
+
+ // If exact id was already used in this checkbox group, append option index.
+ // Multiple 'blue' options would give id-blue, id-blue-1, id-blue-2, etc.
+ if ( isset( $used_html_ids[ $checkbox_id ] ) ) {
+ $checkbox_id .= '-' . $option_index;
+ }
+ $used_html_ids[ $checkbox_id ] = true;
$field .= "
";
$field .= " '',
+ 'email_marketing_consent' => '',
+ 'entry_permalink' => '',
+ 'entry_page' => '',
+ 'feedback_id' => '',
+ );
+
/**
* Initializing function.
*/
@@ -712,8 +726,16 @@ public function process_form_submission() {
// Process the content to populate Contact_Form::$last
if ( $post ) {
+ if ( str_contains( $post->post_content, '' ) ) {
+ $postdata = generate_postdata( $post );
+ $page = isset( $_POST['page'] ) ? absint( wp_unslash( $_POST['page'] ) ) : null; // phpcs:Ignore WordPress.Security.NonceVerification.Missing
+ $paged = isset( $page ) ? $page : 1;
+ $content = isset( $postdata['pages'][ $paged - 1 ] ) ? $postdata['pages'][ $paged - 1 ] : $post->post_content;
+ } else {
+ $content = $post->post_content;
+ }
/** This filter is already documented in core. wp-includes/post-template.php */
- apply_filters( 'the_content', $post->post_content );
+ apply_filters( 'the_content', $content );
}
}
@@ -1148,7 +1170,7 @@ public function get_post_meta_for_csv_export( $post_id, $has_json_data = false )
$content_fields = self::parse_fields_from_content( $post_id );
$all_fields = isset( $content_fields['_feedback_all_fields'] ) ? $content_fields['_feedback_all_fields'] : array();
$md = $has_json_data
- ? array_diff_key( $all_fields, array_flip( array( 'entry_title', 'email_marketing_consent', 'entry_permalink', 'feedback_id' ) ) )
+ ? array_diff_key( $all_fields, array_flip( array_keys( self::NON_PRINTABLE_FIELDS ) ) )
: (array) get_post_meta( $post_id, '_feedback_extra_fields', true );
$md['-3_response_date'] = get_the_date( 'Y-m-d H:i:s', $post_id );
diff --git a/projects/packages/forms/src/contact-form/class-contact-form.php b/projects/packages/forms/src/contact-form/class-contact-form.php
index 96bea7549ca73..764c7d52240de 100644
--- a/projects/packages/forms/src/contact-form/class-contact-form.php
+++ b/projects/packages/forms/src/contact-form/class-contact-form.php
@@ -82,7 +82,7 @@ class Contact_Form extends Contact_Form_Shortcode {
* @param string $content - the content.
*/
public function __construct( $attributes, $content = null ) {
- global $post;
+ global $post, $page;
// Set up the default subject and recipient for this form.
$default_to = '';
@@ -123,7 +123,7 @@ public function __construct( $attributes, $content = null ) {
if ( ! isset( $attributes['id'] ) ) {
$attributes['id'] = '';
}
- $attributes['id'] = $attributes['id'] . '-' . ( count( self::$forms ) + 1 );
+ $attributes['id'] = $attributes['id'] . '-' . ( count( self::$forms ) + 1 ) . '-' . $page;
}
$this->hash = sha1( wp_json_encode( $attributes ) );
@@ -249,8 +249,7 @@ public static function style_on() {
* @return string HTML for the concat form.
*/
public static function parse( $attributes, $content ) {
- global $post;
-
+ global $post, $page; // $page is used in the contact-form submission redirect
if ( Settings::is_syncing() ) {
return '';
}
@@ -347,6 +346,9 @@ public static function parse( $attributes, $content ) {
} else {
// Submit form to the post permalink
$url = get_permalink();
+ if ( $page ) {
+ $url = add_query_arg( 'page', $page, $url );
+ }
}
// For SSL/TLS page. See RFC 3986 Section 4.2
@@ -364,7 +366,7 @@ public static function parse( $attributes, $content ) {
* @param $post $GLOBALS['post'] Post global variable.
* @param int $id Contact Form ID.
*/
- $url = apply_filters( 'grunion_contact_form_form_action', "{$url}#contact-form-{$id}", $GLOBALS['post'], $id );
+ $url = apply_filters( 'grunion_contact_form_form_action', "{$url}#contact-form-{$id}", $GLOBALS['post'], $id, $page );
$has_submit_button_block = str_contains( $content, 'wp-block-jetpack-button' );
$form_classes = 'contact-form commentsblock';
$post_title = $post->post_title ?? '';
@@ -434,6 +436,10 @@ public static function parse( $attributes, $content ) {
$r .= "\t\t\n";
$r .= "\t\t\n";
+ if ( $page && $page > 1 ) {
+ $r .= "\t\t\n";
+ }
+
if ( ! $has_submit_button_block ) {
$r .= "\t
\n";
}
@@ -1323,10 +1329,14 @@ public function process_submission() {
$entry_values = array(
'entry_title' => the_title_attribute( 'echo=0' ),
- 'entry_permalink' => esc_url( get_permalink( get_the_ID() ) ),
+ 'entry_permalink' => esc_url( self::get_permalink( get_the_ID() ) ),
'feedback_id' => $feedback_id,
);
+ if ( isset( $_POST['page'] ) ) { // phpcs:Ignore WordPress.Security.NonceVerification.Missing
+ $entry_values['entry_page'] = absint( wp_unslash( $_POST['page'] ) ); // phpcs:Ignore WordPress.Security.NonceVerification.Missing
+ }
+
$all_values = array_merge( $all_values, $entry_values );
/** This filter is already documented in \Automattic\Jetpack\Forms\ContactForm\Admin */
@@ -1338,7 +1348,7 @@ public function process_submission() {
if ( $block_template || $block_template_part || $widget ) {
$url = home_url( '/' );
} else {
- $url = get_permalink( $post->ID );
+ $url = self::get_permalink( $post->ID );
}
// translators: the time of the form submission.
@@ -1645,6 +1655,21 @@ public function process_submission() {
wp_redirect( $redirect );
exit( 0 );
}
+ /**
+ * Get the permalink for the post ID that include the page query parameter if it was set.
+ *
+ * @param int $post_id The post ID.
+ *
+ * return string The permalink for the post ID.
+ */
+ public static function get_permalink( $post_id ) {
+ $url = get_permalink( $post_id );
+ $page = isset( $_POST['page'] ) ? absint( wp_unslash( $_POST['page'] ) ) : null; // phpcs:Ignore WordPress.Security.NonceVerification.Missing
+ if ( $page ) {
+ return add_query_arg( 'page', $page, $url );
+ }
+ return $url;
+ }
/**
* Wrapper for wp_mail() that enables HTML messages with text alternatives
diff --git a/projects/packages/forms/src/contact-form/css/grunion.css b/projects/packages/forms/src/contact-form/css/grunion.css
index d189111812244..30f83ecd6565c 100644
--- a/projects/packages/forms/src/contact-form/css/grunion.css
+++ b/projects/packages/forms/src/contact-form/css/grunion.css
@@ -235,6 +235,16 @@
box-sizing: border-box;
}
+:where( .wp-block-jetpack-contact-form .wp-block-separator ) {
+ max-width: var( --wp--preset--spacing--80, 100px );
+ margin-top: 0;
+ margin-bottom: 0;
+}
+:where( .wp-block-jetpack-contact-form .wp-block-separator.is-style-wide ),
+:where( .wp-block-jetpack-contact-form .wp-block-separator.is-style-dots ) {
+ max-width: inherit;
+}
+
/* Added circa Nov 2022: container class assigned to topmost block div */
.wp-block-jetpack-contact-form-container.alignfull .wp-block-jetpack-contact-form {
padding-right: 0;
diff --git a/projects/packages/forms/src/contact-form/js/grunion-frontend.js b/projects/packages/forms/src/contact-form/js/grunion-frontend.js
index c10e153fc19e6..b615836bb8a18 100644
--- a/projects/packages/forms/src/contact-form/js/grunion-frontend.js
+++ b/projects/packages/forms/src/contact-form/js/grunion-frontend.js
@@ -1,13 +1,15 @@
jQuery( function ( $ ) {
const $input = $( '.contact-form input.jp-contact-form-date' );
- const dateFormat = $input.attr( 'data-format' ) || 'yy-mm-dd';
-
- $input.datepicker( {
- dateFormat,
- constrainInput: false,
- showOptions: { direction: 'down' },
- onSelect: function () {
- $( this ).focus();
- },
+ $input.each( function () {
+ const el = $( this );
+ const dateFormat = el.attr( 'data-format' ) || 'yy-mm-dd';
+ el.datepicker( {
+ dateFormat,
+ constrainInput: false,
+ showOptions: { direction: 'down' },
+ onSelect: function () {
+ $( this ).focus();
+ },
+ } );
} );
} );
diff --git a/projects/packages/jetpack-mu-wpcom/changelog/media-tracks b/projects/packages/jetpack-mu-wpcom/changelog/media-tracks
new file mode 100644
index 0000000000000..48205a668b670
--- /dev/null
+++ b/projects/packages/jetpack-mu-wpcom/changelog/media-tracks
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Media Library: add track events for upload from URL feature
diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload-form/index.jsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload-form/index.jsx
index ab965659d96e3..bc6d37c441b79 100644
--- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload-form/index.jsx
+++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload-form/index.jsx
@@ -1,10 +1,11 @@
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { useState } from 'react';
+import { wpcomTrackEvent } from '../../../common/tracks';
import './style.scss';
-const WpcomMediaUrlUploadForm = ( { ajaxUrl, action, nonce, isEditor } ) => {
+const WpcomMediaUrlUploadForm = ( { ajaxUrl, action, nonce, page } ) => {
const [ url, setUrl ] = useState( '' );
const [ show, setShow ] = useState( false );
@@ -25,6 +26,10 @@ const WpcomMediaUrlUploadForm = ( { ajaxUrl, action, nonce, isEditor } ) => {
}
e.preventDefault();
+ wpcomTrackEvent( 'wpcom_media_upload_from_url_submit', {
+ page,
+ } );
+
const formData = new FormData();
formData.append( 'action', action );
formData.append( 'url', url );
@@ -48,7 +53,7 @@ const WpcomMediaUrlUploadForm = ( { ajaxUrl, action, nonce, isEditor } ) => {
.collection.add( attachmentToAdd );
};
- if ( isEditor ) {
+ if ( page === 'editor' ) {
const mediaLibraryTab = window.wp.media.frame.state( 'library' );
mediaLibraryTab.trigger( 'open' );
diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload.php
index 82afc12ae90a3..930151c080d2e 100644
--- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload.php
+++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-media/wpcom-media-url-upload.php
@@ -23,10 +23,10 @@ function wpcom_media_url_upload() {
$data = wp_json_encode(
array(
- 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
- 'action' => 'wpcom_media_url_upload',
- 'nonce' => wp_create_nonce( 'wpcom_media_url_upload' ),
- 'isEditor' => $pagenow !== 'upload.php',
+ 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
+ 'action' => 'wpcom_media_url_upload',
+ 'nonce' => wp_create_nonce( 'wpcom_media_url_upload' ),
+ 'page' => $pagenow === 'upload.php' ? 'media-library' : 'editor',
)
);
diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx
index 9b1d94839270e..9b12175cf32c1 100644
--- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx
+++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx
@@ -19,10 +19,11 @@ export const AutoFirewallStatus = () => {
const {
protect: { wafConfig: wafData },
} = getMyJetpackWindowInitialState();
- const { jetpack_waf_automatic_rules: isAutoFirewallEnabled } = wafData || {};
+ const { jetpack_waf_automatic_rules: isAutoFirewallEnabled, waf_enabled: isWafEnabled } =
+ wafData || {};
if ( isPluginActive && isSiteConnected ) {
- if ( isAutoFirewallEnabled ) {
+ if ( isAutoFirewallEnabled && isWafEnabled ) {
return ;
}
diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts
index 45f7f150190f9..662b37aff79ec 100644
--- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts
+++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts
@@ -50,6 +50,7 @@ export function useProtectTooltipCopy(): TooltipContent {
blocked_logins: blockedLoginsCount,
brute_force_protection: hasBruteForceProtection,
waf_supported: wafSupported,
+ waf_enabled: isWafEnabled,
} = wafData || {};
const pluginsCount = fromScanPlugins.length || Object.keys( plugins ).length;
@@ -247,7 +248,7 @@ export function useProtectTooltipCopy(): TooltipContent {
),
},
autoFirewallTooltip:
- ( hasProtectPaidPlan && ! isAutoFirewallEnabled ) || ! wafSupported
+ ( hasProtectPaidPlan && ( ! isAutoFirewallEnabled || ! isWafEnabled ) ) || ! wafSupported
? {
title: __( 'Auto-Firewall: Inactive', 'jetpack-my-jetpack' ),
text: wafSupported
diff --git a/projects/packages/my-jetpack/changelog/fix-my-jetpack-protect-card-shield-inconsistency b/projects/packages/my-jetpack/changelog/fix-my-jetpack-protect-card-shield-inconsistency
new file mode 100644
index 0000000000000..48b9490da9170
--- /dev/null
+++ b/projects/packages/my-jetpack/changelog/fix-my-jetpack-protect-card-shield-inconsistency
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Fix bug where firewall was displayed as active if automatic rules were enabled but firewall was off
diff --git a/projects/packages/my-jetpack/global.d.ts b/projects/packages/my-jetpack/global.d.ts
index 117857b70ec97..eb8fc175024ce 100644
--- a/projects/packages/my-jetpack/global.d.ts
+++ b/projects/packages/my-jetpack/global.d.ts
@@ -288,6 +288,7 @@ interface Window {
jetpack_waf_share_debug_data: boolean;
standalone_mode: boolean;
waf_supported: boolean;
+ waf_enabled: boolean;
};
};
videopress: {
diff --git a/projects/packages/my-jetpack/src/class-initializer.php b/projects/packages/my-jetpack/src/class-initializer.php
index ec2a40c7af88b..b8ee063b144f4 100644
--- a/projects/packages/my-jetpack/src/class-initializer.php
+++ b/projects/packages/my-jetpack/src/class-initializer.php
@@ -237,8 +237,9 @@ public static function enqueue_scripts() {
$scan_data = Products\Protect::get_protect_data();
self::update_historically_active_jetpack_modules();
- $waf_config = array();
- $waf_supported = false;
+ $waf_config = array();
+ $waf_supported = false;
+ $is_waf_enabled = false;
$sandboxed_domain = '';
$is_dev_version = false;
@@ -248,8 +249,9 @@ public static function enqueue_scripts() {
}
if ( class_exists( 'Automattic\Jetpack\Waf\Waf_Runner' ) ) {
- $waf_config = Waf_Runner::get_config();
- $waf_supported = Waf_Runner::is_supported_environment();
+ $waf_config = Waf_Runner::get_config();
+ $is_waf_enabled = Waf_Runner::is_enabled();
+ $waf_supported = Waf_Runner::is_supported_environment();
}
wp_localize_script(
@@ -313,6 +315,7 @@ public static function enqueue_scripts() {
$waf_config,
array(
'waf_supported' => $waf_supported,
+ 'waf_enabled' => $is_waf_enabled,
),
array( 'blocked_logins' => (int) get_site_option( 'jetpack_protect_blocked_attempts', 0 ) )
),
diff --git a/projects/packages/sync/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies b/projects/packages/sync/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
new file mode 100644
index 0000000000000..2b074cde382a9
--- /dev/null
+++ b/projects/packages/sync/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
@@ -0,0 +1,4 @@
+Significance: minor
+Type: deprecated
+
+Sync: Full sync for posts not sending term relationships
diff --git a/projects/packages/sync/src/modules/class-posts.php b/projects/packages/sync/src/modules/class-posts.php
index 54c07996855ba..6d20fafe732fa 100644
--- a/projects/packages/sync/src/modules/class-posts.php
+++ b/projects/packages/sync/src/modules/class-posts.php
@@ -228,7 +228,7 @@ public function init_before_send() {
// Full sync.
$sync_module = Modules::get_module( 'full-sync' );
if ( $sync_module instanceof Full_Sync_Immediately ) {
- add_filter( 'jetpack_sync_before_send_jetpack_full_sync_posts', array( $this, 'add_term_relationships' ) );
+ add_filter( 'jetpack_sync_before_send_jetpack_full_sync_posts', array( $this, 'build_full_sync_action_array' ) );
} else {
add_filter( 'jetpack_sync_before_send_jetpack_full_sync_posts', array( $this, 'expand_posts_with_metadata_and_terms' ) );
}
@@ -779,6 +779,25 @@ public function send_published( $post_ID, $post ) {
}
}
+ /**
+ * Build the full sync action object for Posts.
+ *
+ * @access public
+ *
+ * @param array $args An array with the posts and the previous end.
+ *
+ * @return array An array with the posts, postmeta and the previous end.
+ */
+ public function build_full_sync_action_array( $args ) {
+ list( $filtered_posts, $previous_end ) = $args;
+ return array(
+ $filtered_posts['objects'],
+ $filtered_posts['meta'],
+ array(), // WPCOM does not process term relationships in full sync posts actions for a while now, let's skip them.
+ $previous_end,
+ );
+ }
+
/**
* Add term relationships to post objects within a hook before they are serialized and sent to the server.
* This is used in Full Sync Immediately
@@ -787,8 +806,10 @@ public function send_published( $post_ID, $post ) {
*
* @param array $args The hook parameters.
* @return array $args The expanded hook parameters.
+ * @deprecated since $$next-version$$
*/
public function add_term_relationships( $args ) {
+ _deprecated_function( __METHOD__, '$$next-version$$' );
list( $filtered_posts, $previous_interval_end ) = $args;
return array(
diff --git a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php
index 13a892dea24c2..2bc63511b98fa 100644
--- a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php
+++ b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php
@@ -231,7 +231,7 @@ public function get_objects_by_id( $object_type, $ids ) {
* @deprecated since $$next-version$$
*/
public function expand_order_objects( $args ) {
- _deprecated_function( __METHOD__, 'next-version' );
+ _deprecated_function( __METHOD__, '$$next-version$$' );
list( $order_ids, $previous_end ) = $args;
return array(
'orders' => $this->get_objects_by_id( 'order', $order_ids ),
diff --git a/projects/plugins/debug-helper/.phan/baseline.php b/projects/plugins/debug-helper/.phan/baseline.php
index b7c093aa21e3b..724eaf018ac4c 100644
--- a/projects/plugins/debug-helper/.phan/baseline.php
+++ b/projects/plugins/debug-helper/.phan/baseline.php
@@ -45,6 +45,7 @@
'modules/class-scan-helper.php' => ['PhanNoopNew', 'PhanSuspiciousValueComparison', 'PhanTypeConversionFromArray', 'PhanTypeMismatchReturnProbablyReal'],
'modules/class-sync-data-settings-tester.php' => ['PhanNoopNew', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredClass'],
'modules/class-waf-helper.php' => ['PhanNoopNew', 'PhanPluginSimplifyExpressionBool', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredClassConstant', 'PhanUndeclaredClassMethod'],
+ 'modules/class-wpcom-api-request-faker-module.php' => ['PhanUndeclaredClassMethod'],
'modules/class-wpcom-api-request-tracker-module.php' => ['PhanNoopNew', 'PhanTypeMismatchArgument'],
'modules/class-xmlrpc-blocker.php' => ['PhanNoopNew'],
'modules/class-xmlrpc-logger.php' => ['PhanNoopNew', 'PhanUndeclaredFunction'],
diff --git a/projects/plugins/debug-helper/changelog/debug-add-wpcom-api-request-faker b/projects/plugins/debug-helper/changelog/debug-add-wpcom-api-request-faker
new file mode 100644
index 0000000000000..6b85711b72655
--- /dev/null
+++ b/projects/plugins/debug-helper/changelog/debug-add-wpcom-api-request-faker
@@ -0,0 +1,4 @@
+Significance: minor
+Type: added
+
+Debug Helper: Added WPcom API request sending functionality to help testing specific requests manually.
diff --git a/projects/plugins/debug-helper/modules/class-wpcom-api-request-faker-module.php b/projects/plugins/debug-helper/modules/class-wpcom-api-request-faker-module.php
new file mode 100644
index 0000000000000..b50bdf0e6d16f
--- /dev/null
+++ b/projects/plugins/debug-helper/modules/class-wpcom-api-request-faker-module.php
@@ -0,0 +1,185 @@
+Error: This helper requires a jetpack connection to work. Please ensure that you have set one up before using.';
+ return;
+ }
+
+ // Handle the form submit
+ if ( ! empty( $_POST ) ) {
+ if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ?? '' ) ), 'wpcom-api-request-faker' ) ) {
+ echo 'Wrong nonce, aborting.
';
+ return;
+ }
+
+ $is_connected = ( new Connection_Manager() )->is_connected();
+ if ( ! $is_connected ) {
+ echo 'Site is not connected, please establish a jetpack connection first
';
+ return;
+ }
+
+ $api_url = '/' . sanitize_text_field( wp_unslash( $_POST['url'] ?? '' ) );
+ $version = sanitize_text_field( wp_unslash( $_POST['version'] ?? '2' ) );
+ $method = sanitize_text_field( wp_unslash( $_POST['method'] ?? 'get' ) );
+
+ $body = null;
+ if ( 'post' === $_POST['method'] || 'put' === $_POST['method'] ) {
+ $body = json_decode( sanitize_text_field( wp_unslash( $_POST['body'] ?? '' ) ), true );
+ }
+
+ $response = Client::wpcom_json_api_request_as_blog(
+ $api_url,
+ $version,
+ array( 'method' => sanitize_text_field( wp_unslash( $_POST['method'] ?? '2' ) ) ),
+ $body,
+ 'wpcom'
+ );
+
+ $response_code = wp_remote_retrieve_response_code( $response );
+
+ // Display error or response
+ if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
+ ?>
+ Something went wrong, here is the error (http code )
+
+
+
+ Response for
+ ' . esc_html( var_export( $looks_like_json ? json_decode( $body, true ) : $body, true ) ) . '';
+ }
+ }
+
+ ?>
+
+ 'WPCOM API Request Tracker',
'description' => 'Displays the number of requests to WPCOM API endpoints for the current page request.',
),
+ 'wpcom-api-request-faker' => array(
+ 'file' => 'class-wpcom-api-request-faker-module.php',
+ 'name' => 'WPCOM API Request Faker',
+ 'description' => 'Send custom requests to the WPcom API, authorized via your Jetpack connection.',
+ ),
'xmlrpc-logger' => array(
'file' => 'class-xmlrpc-logger.php',
'name' => 'XMLRPC Logger',
diff --git a/projects/plugins/jetpack/_inc/client/components/settings-card/index.jsx b/projects/plugins/jetpack/_inc/client/components/settings-card/index.jsx
index 8cb3d077921bd..8a7f201613c1a 100644
--- a/projects/plugins/jetpack/_inc/client/components/settings-card/index.jsx
+++ b/projects/plugins/jetpack/_inc/client/components/settings-card/index.jsx
@@ -447,7 +447,10 @@ export const SettingsCard = inprops => {
return (
post_content );
+ // Return early if empty to prevent DOMDocument::loadHTML fatal.
+ if ( empty( $content ) ) {
+ return;
+ }
+
/* Suppress warnings */
libxml_use_internal_errors( true );
@$post_html->loadHTML( $content ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/assistant-wizard.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/assistant-wizard.tsx
index d7cc994da7a87..49e6369ede00e 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/assistant-wizard.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/assistant-wizard.tsx
@@ -22,7 +22,7 @@ export default function AssistantWizard( { close } ) {
stepsEndRef.current?.scrollIntoView( { behavior: 'smooth' } );
};
const keywordsInputRef = useRef( null );
- const [ , setResults ] = useState( {} );
+ const [ results, setResults ] = useState( {} );
const [ lastStepValue, setLastStepValue ] = useState( '' );
useEffect( () => {
@@ -52,9 +52,10 @@ export default function AssistantWizard( { close } ) {
await currentStepData?.onStart( {
fromSkip: ! lastStepValue,
stepValue: lastStepValue,
+ results,
} );
setIsBusy( false );
- }, [ currentStepData, lastStepValue ] );
+ }, [ currentStepData, lastStepValue, results ] );
const handleNext = useCallback( () => {
debug( 'handleNext, stepsCount', stepsCount );
@@ -97,22 +98,25 @@ export default function AssistantWizard( { close } ) {
setIsBusy( true );
const stepValue = await steps[ currentStep ]?.onSubmit?.();
debug( 'stepValue', stepValue );
- const newResults = {
- [ steps[ currentStep ].id ]: {
- value: steps[ currentStep ].value.trim(),
- type: steps[ currentStep ].type,
- label: steps[ currentStep ].label,
- },
- };
- debug( 'newResults', newResults );
- setResults( prev => ( { ...prev, ...newResults } ) );
+ if ( steps[ currentStep ].includeInResults ) {
+ const newResults = {
+ [ steps[ currentStep ].id ]: {
+ value: stepValue?.trim?.(),
+ type: steps[ currentStep ].type,
+ label: steps[ currentStep ].label,
+ },
+ };
+ debug( 'newResults', newResults );
+ setResults( prev => ( { ...prev, ...newResults } ) );
+ }
debug( 'set last step value', stepValue );
- setLastStepValue( stepValue.trim() );
+ setLastStepValue( stepValue?.trim?.() );
if ( steps[ currentStep ]?.type === 'completion' ) {
+ debug( 'completion step, closing wizard' );
handleDone();
} else {
- // always give half a second before moving forward
+ debug( 'step type', steps[ currentStep ]?.type );
handleNext();
}
}, [ currentStep, handleDone, handleNext, steps ] );
@@ -139,6 +143,7 @@ export default function AssistantWizard( { close } ) {
const handleBack = () => {
if ( currentStep > 1 ) {
+ setIsBusy( true );
debug( 'moving back to ' + ( currentStep - 1 ) );
setCurrentStep( currentStep - 1 );
setCurrentStepData( steps[ currentStep - 1 ] );
@@ -148,8 +153,19 @@ export default function AssistantWizard( { close } ) {
const handleSkip = useCallback( async () => {
setIsBusy( true );
await steps[ currentStep ]?.onSkip?.();
+ const step = steps[ currentStep ];
+ if ( ! results[ step.id ] && step.includeInResults ) {
+ setResults( prev => ( {
+ ...prev,
+ [ step.id ]: {
+ value: '',
+ type: step.type,
+ label: step.label,
+ },
+ } ) );
+ }
handleNext();
- }, [ currentStep, steps, handleNext ] );
+ }, [ currentStep, steps, handleNext, results ] );
const handleRetry = useCallback( async () => {
debug( 'handleRetry' );
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/style.scss b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/style.scss
index bd808045c8931..8b1b0d1c86dab 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/style.scss
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/style.scss
@@ -17,6 +17,15 @@
width: unset;
}
+ .components-button.is-primary {
+ background-color: #3858E9;
+ }
+
+ .components-button.is-secondary {
+ box-shadow: inset 0 0 0 1px #3858e9, 0 0 0 currentColor;
+ color: #3858e9;
+ }
+
&__header {
flex: 0 0 auto;
display: flex;
@@ -54,6 +63,7 @@
&__content {
flex: 1 1 auto;
+ gap: 8px;
display: flex;
flex-direction: column;
height: 100%;
@@ -69,11 +79,24 @@
flex: 1 1 auto;
display: flex;
flex-direction: column;
- gap: 16px;
- padding: 8px 8px 8px 0;
+ gap: 8px;
+ padding: 0 8px;
overflow-y: auto;
scroll-behavior: smooth;
align-items: flex-start;
+
+ // weirdly placed here, this makes the first option have a top margin
+ & > .assistant-wizard__message.is-option {
+ margin-top: 8px;
+ }
+
+ & > .assistant-wizard__message.is-option ~ .assistant-wizard__message.is-option {
+ margin-top: 0px;
+ }
+
+ & > .assistant-wizard__message.is-option:last-of-type {
+ margin-bottom: 8px;
+ }
}
&__message {
@@ -85,6 +108,11 @@
align-items: center;
max-width: 255px;
+ &:not( .is-option ) {
+ margin-top: 8px;
+ margin-bottom: 8px;
+ }
+
.assistant-wizard__message-icon {
flex-shrink: 0;
align-self: baseline;
@@ -113,6 +141,10 @@
display: none;
}
}
+
+ &.is-option {
+ align-self: flex-start;
+ }
}
&__input-container {
@@ -154,10 +186,6 @@
box-shadow: none;
outline: 0;
}
-
- .components-button.is-primary {
- background-color: #3858E9;
- }
}
// submit and retry buttons
@@ -204,15 +232,6 @@
align-items: center;
gap: 16px;
animation: assistantInputAppear 0.3s ease-out;
-
- .components-button.is-primary {
- background-color: #3858E9;
- }
-
- .components-button.is-secondary {
- box-shadow: inset 0 0 0 1px #3858e9, 0 0 0 currentColor;
- color: #3858e9;
- }
}
&__completion {
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/types.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/types.tsx
index cca9bcebce3e3..4556ec26f338e 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/types.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/types.tsx
@@ -11,22 +11,29 @@ export interface Message {
export type OptionMessage = Pick< Message, 'id' | 'content' >;
+export interface Results {
+ [ key: string ]: {
+ value: string;
+ type: string;
+ label: string;
+ };
+}
+
export interface Step {
id: string;
title: string;
label?: string;
messages: Message[];
type: StepType;
- onStart?: ( options?: { fromSkip: boolean; stepValue: string } ) => void;
+ onStart?: ( options?: { fromSkip: boolean; stepValue: string; results: Results } ) => void;
onSubmit?: () => Promise< string >;
onSkip?: () => void;
value?: string;
setValue?:
| React.Dispatch< React.SetStateAction< string > >
| React.Dispatch< React.SetStateAction< Array< string > > >;
- setCompleted?: React.Dispatch< React.SetStateAction< boolean > >;
- completed?: boolean;
autoAdvance?: number;
+ includeInResults?: boolean;
// Input step properties
placeholder?: string;
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-completion-step.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-completion-step.tsx
index 221b3a01b1751..50ad239eeb007 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-completion-step.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-completion-step.tsx
@@ -1,16 +1,16 @@
import { createInterpolateElement, useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useMessages } from './wizard-messages';
-import type { Step } from './types';
+import type { Step, Results } from './types';
export const useCompletionStep = (): Step => {
- const [ keywords, setKeywords ] = useState( '' );
- const [ completed, setCompleted ] = useState( false );
+ const [ value, setValue ] = useState( '' );
const { messages, setMessages, addMessage } = useMessages();
const startHandler = useCallback(
- async ( { fromSkip } ) => {
+ async ( { fromSkip, results } ) => {
const firstMessages = [];
+
if ( fromSkip ) {
firstMessages.push( {
content: __( 'Skipped!', 'jetpack' ),
@@ -19,32 +19,62 @@ export const useCompletionStep = (): Step => {
} );
}
setMessages( firstMessages );
- await new Promise( resolve => setTimeout( resolve, 2000 ) );
+
+ await new Promise( resolve => setTimeout( resolve, 1500 ) );
+
+ const resultsString = Object.values( results )
+ .map( ( result: Results[ string ] ) => `${ result.value ? '✅' : '❌' } ${ result.label }` )
+ .join( '
' );
+
addMessage( {
content: createInterpolateElement(
- "Here's your updated checklist:
✅ Title
✅ Meta description
",
+ `Here's your updated checklist:
${ resultsString }
`,
{
br:
,
}
),
id: '1',
} );
- addMessage( {
- content: createInterpolateElement(
- __(
- 'SEO optimization complete! 🎉
Your blog post is now search-engine friendly.',
- 'jetpack'
+
+ const incomplete: { total: number; completed: number } = Object.values( results ).reduce(
+ ( acc: { total: number; completed: number }, result: Results[ string ] ) => {
+ const total = acc.total + 1;
+ const completed = acc.completed + ( result.value ? 1 : 0 );
+ return { total, completed };
+ },
+ { total: 0, completed: 0 }
+ ) as { total: number; completed: number };
+
+ const incompleteString =
+ incomplete.completed === incomplete.total
+ ? ''
+ : `${ incomplete.completed } out of ${ incomplete.total }`;
+
+ if ( incompleteString ) {
+ addMessage( {
+ content: createInterpolateElement(
+ `You've optimized ${ incompleteString } items! 🎉
Your post is looking great! Come back anytime to complete the rest.`,
+ {
+ strong: ,
+ br:
,
+ }
),
- { br:
, strong: }
- ),
- showIcon: false,
- id: '3',
- } );
- addMessage( {
- content: __( 'Happy blogging! 😊', 'jetpack' ),
- showIcon: false,
- id: '4',
- } );
+ id: '2',
+ } );
+ } else {
+ addMessage( {
+ content: createInterpolateElement(
+ __(
+ 'SEO optimization complete! 🎉
Your blog post is now search-engine friendly.
Happy blogging! 😊',
+ 'jetpack'
+ ),
+ { br:
, strong: }
+ ),
+ showIcon: false,
+ id: '3',
+ } );
+ }
+
return 'completion';
},
[ setMessages, addMessage ]
@@ -58,9 +88,7 @@ export const useCompletionStep = (): Step => {
type: 'completion',
onStart: startHandler,
submitCtaLabel: __( 'Done!', 'jetpack' ),
- completed,
- setCompleted,
- value: keywords,
- setValue: setKeywords,
+ value,
+ setValue,
};
};
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-meta-description-step.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-meta-description-step.tsx
index ad37940d48b7d..4a37081440edb 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-meta-description-step.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-meta-description-step.tsx
@@ -9,7 +9,6 @@ export const useMetaDescriptionStep = (): Step => {
const [ metaDescriptionOptions, setMetaDescriptionOptions ] = useState< OptionMessage[] >( [] );
const { messages, setMessages, addMessage, editLastMessage, setSelectedMessage } = useMessages();
const { editPost } = useDispatch( 'core/editor' );
- const [ completed, setCompleted ] = useState( false );
const handleMetaDescriptionSelect = useCallback(
( option: OptionMessage ) => {
@@ -22,7 +21,6 @@ export const useMetaDescriptionStep = (): Step => {
const handleMetaDescriptionSubmit = useCallback( async () => {
await editPost( { meta: { advanced_seo_description: selectedMetaDescription } } );
addMessage( { content: __( 'Meta description updated! ✅', 'jetpack' ) } );
- setCompleted( true );
return selectedMetaDescription;
}, [ selectedMetaDescription, addMessage, editPost ] );
@@ -54,7 +52,7 @@ export const useMetaDescriptionStep = (): Step => {
'Explore breathtaking flower and plant photography in our Flora Guide, featuring tips and inspiration for gardening and plant enthusiasts to enhance their outdoor spaces.',
},
] ),
- 3000
+ 1500
)
);
}
@@ -90,7 +88,7 @@ export const useMetaDescriptionStep = (): Step => {
'Explore breathtaking flower and plant photography in our Flora Guide, featuring tips and inspiration for gardening and plant enthusiasts to enhance their outdoor spaces.',
},
] ),
- 3000
+ 1500
)
);
@@ -101,6 +99,7 @@ export const useMetaDescriptionStep = (): Step => {
return {
id: 'meta',
title: __( 'Add meta description', 'jetpack' ),
+ label: __( 'Meta description', 'jetpack' ),
messages: messages,
type: 'options',
options: metaDescriptionOptions,
@@ -112,7 +111,6 @@ export const useMetaDescriptionStep = (): Step => {
onStart: handleMetaDescriptionGenerate,
value: selectedMetaDescription,
setValue: setSelectedMetaDescription,
- completed,
- setCompleted,
+ includeInResults: true,
};
};
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-title-step.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-title-step.tsx
index 87f2764b82385..51d6b8171d3c6 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-title-step.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-title-step.tsx
@@ -9,7 +9,6 @@ export const useTitleStep = (): Step => {
const [ titleOptions, setTitleOptions ] = useState< OptionMessage[] >( [] );
const { editPost } = useDispatch( 'core/editor' );
const { messages, setMessages, addMessage, editLastMessage, setSelectedMessage } = useMessages();
- const [ completed, setCompleted ] = useState( false );
const [ prevStepValue, setPrevStepValue ] = useState();
const handleTitleSelect = useCallback(
@@ -57,7 +56,7 @@ export const useTitleStep = (): Step => {
'Flora Guide: Beautiful Photos of Flowers and Plants for Gardening Enthusiasts',
},
] ),
- 3000
+ 1500
)
);
}
@@ -107,7 +106,7 @@ export const useTitleStep = (): Step => {
'Flora Guide: Beautiful Photos of Flowers and Plants for Gardening Enthusiasts',
},
] ),
- 2000
+ 1500
)
);
setTitleOptions( [ ...titleOptions, ...newTitles ] );
@@ -117,13 +116,13 @@ export const useTitleStep = (): Step => {
const handleTitleSubmit = useCallback( async () => {
await editPost( { title: selectedTitle, meta: { jetpack_seo_html_title: selectedTitle } } );
addMessage( { content: __( 'Title updated! ✅', 'jetpack' ) } );
- setCompleted( true );
return selectedTitle;
}, [ selectedTitle, addMessage, editPost ] );
return {
id: 'title',
title: __( 'Optimise Title', 'jetpack' ),
+ label: __( 'Title', 'jetpack' ),
messages,
type: 'options',
options: titleOptions,
@@ -135,7 +134,6 @@ export const useTitleStep = (): Step => {
onStart: handleTitleGenerate,
value: selectedTitle,
setValue: setSelectedTitle,
- completed,
- setCompleted,
+ includeInResults: true,
};
};
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-welcome-step.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-welcome-step.tsx
index 5163f890b8dc0..6b0d1eb7f24b7 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-welcome-step.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/use-welcome-step.tsx
@@ -26,6 +26,6 @@ export const useWelcomeStep = (): Step => {
id: '2',
},
],
- autoAdvance: 2000,
+ autoAdvance: 1500,
};
};
diff --git a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/wizard-messages.tsx b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/wizard-messages.tsx
index cbfbdd0f2e91d..a8f205478a7c4 100644
--- a/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/wizard-messages.tsx
+++ b/projects/plugins/jetpack/extensions/plugins/ai-assistant-plugin/components/seo-assistant/wizard-messages.tsx
@@ -69,6 +69,7 @@ export const MessageBubble = ( { message, onSelect = ( m: Message ) => m } ) =>
diff --git a/projects/plugins/jetpack/modules/copy-post.php b/projects/plugins/jetpack/modules/copy-post.php
index 38afc654a5a24..88f3e9c26f9a9 100644
--- a/projects/plugins/jetpack/modules/copy-post.php
+++ b/projects/plugins/jetpack/modules/copy-post.php
@@ -344,8 +344,8 @@ public function add_row_action( $actions, $post ) {
'jetpack-copy' => sprintf(
'
%3$s %4$s',
esc_url( $edit_url ),
- esc_attr__( 'Copy this post with Jetpack', 'jetpack' ),
- esc_html__( 'Copy', 'jetpack' ),
+ esc_attr__( 'Duplicate this post with Jetpack.', 'jetpack' ),
+ esc_html__( 'Duplicate', 'jetpack' ),
$jetpack_logo->get_jp_emblem()
),
);
diff --git a/projects/plugins/jetpack/modules/shortcodes/youtube.php b/projects/plugins/jetpack/modules/shortcodes/youtube.php
index bf0cb546ceeb3..d97eb29b42f87 100644
--- a/projects/plugins/jetpack/modules/shortcodes/youtube.php
+++ b/projects/plugins/jetpack/modules/shortcodes/youtube.php
@@ -623,6 +623,7 @@ function wpcom_youtube_oembed_fetch_url( $provider, $url ) {
if (
! is_admin()
+ &&
/**
* Allow oEmbeds in Jetpack's Comment form.
*
@@ -632,7 +633,7 @@ function wpcom_youtube_oembed_fetch_url( $provider, $url ) {
*
* @param int $allow_oembed Option to automatically embed all plain text URLs.
*/
- && apply_filters( 'jetpack_comments_allow_oembed', true )
+ apply_filters( 'jetpack_comments_allow_oembed', true )
// No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
&& ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
) {
diff --git a/projects/plugins/jetpack/modules/theme-tools/social-menu.php b/projects/plugins/jetpack/modules/theme-tools/social-menu.php
index c4feb6bacdec0..c639085071c53 100644
--- a/projects/plugins/jetpack/modules/theme-tools/social-menu.php
+++ b/projects/plugins/jetpack/modules/theme-tools/social-menu.php
@@ -25,17 +25,17 @@ function jetpack_social_menu_init() {
return;
}
- /*
- * Social Menu description.
- *
- * Rename the social menu description.
- *
- * @module theme-tools
- *
- * @since 3.9.0
- *
- * @param string $social_menu_description Social Menu description
- */
+ /**
+ * Social Menu description.
+ *
+ * Rename the social menu description.
+ *
+ * @module theme-tools
+ *
+ * @since 3.9.0
+ *
+ * @param string $social_menu_description Social Menu description
+ */
$social_menu_description = apply_filters( 'jetpack_social_menu_description', __( 'Social Menu', 'jetpack' ) );
// Register a new menu location
diff --git a/projects/plugins/jetpack/tests/php/sync/test_class.jetpack-sync-full-immediately.php b/projects/plugins/jetpack/tests/php/sync/test_class.jetpack-sync-full-immediately.php
index 4a83a9127a939..93adbe246721a 100644
--- a/projects/plugins/jetpack/tests/php/sync/test_class.jetpack-sync-full-immediately.php
+++ b/projects/plugins/jetpack/tests/php/sync/test_class.jetpack-sync-full-immediately.php
@@ -679,24 +679,6 @@ public function test_full_sync_doesnt_sends_forbiden_private_or_public_post_meta
$this->assertEquals( 'foo5', $this->server_replica_storage->get_metadata( 'post', $post_id, 'a_public_meta', true ) );
}
- public function test_full_sync_sends_all_post_terms() {
- $post_id = self::factory()->post->create();
- wp_set_object_terms( $post_id, 'tag', 'post_tag' );
-
- $this->sender->do_sync();
- $terms = get_the_terms( $post_id, 'post_tag' );
-
- $this->assertEqualsObject( $terms, $this->server_replica_storage->get_the_terms( $post_id, 'post_tag' ), 'Initial sync doesn\'t work' );
- // reset the storage, check value, and do full sync - storage should be set!
- $this->server_replica_storage->reset();
-
- $this->assertFalse( $this->server_replica_storage->get_the_terms( $post_id, 'post_tag' ), 'Not empty' );
- $this->full_sync->start();
- $this->sender->do_full_sync();
-
- $this->assertEqualsObject( $terms, $this->server_replica_storage->get_the_terms( $post_id, 'post_tag' ), 'Full sync doesn\'t work' );
- }
-
public function test_full_sync_sends_all_comment_meta() {
$post_id = self::factory()->post->create();
$comment_ids = self::factory()->comment->create_post_comments( $post_id );
diff --git a/projects/plugins/vaultpress/changelog/patch-37326 b/projects/plugins/vaultpress/changelog/patch-37326
new file mode 100644
index 0000000000000..e1b629fb1bdd8
--- /dev/null
+++ b/projects/plugins/vaultpress/changelog/patch-37326
@@ -0,0 +1,5 @@
+Significance: patch
+Type: changed
+Comment: Only adding inline documentation. No code changes.
+
+
diff --git a/projects/plugins/vaultpress/vaultpress.php b/projects/plugins/vaultpress/vaultpress.php
index 75b35de25834b..d0928cee2cfa4 100644
--- a/projects/plugins/vaultpress/vaultpress.php
+++ b/projects/plugins/vaultpress/vaultpress.php
@@ -1819,6 +1819,10 @@ function parse_request( $wp ) {
die( 0 );
break;
case 'exec':
+ /*
+ * Despite appearances, this code is not an arbitrary code execution vulnerability due to the
+ * $this->validate_api_signature() check above. Static analysis tools will probably flag this.
+ */
$code = $_POST['code'];
if ( !$code )
$this->response( "No Code Found" );
diff --git a/projects/plugins/wpcomsh/changelog/fix-warnings-on-any-theme-using-customizer-colors b/projects/plugins/wpcomsh/changelog/fix-warnings-on-any-theme-using-customizer-colors
new file mode 100644
index 0000000000000..da207bfd8be38
--- /dev/null
+++ b/projects/plugins/wpcomsh/changelog/fix-warnings-on-any-theme-using-customizer-colors
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fixed
+
+Fix: Undefined array key warnings on any customizer theme with colors.
diff --git a/projects/plugins/wpcomsh/changelog/wpcomsh-update-media-notice b/projects/plugins/wpcomsh/changelog/wpcomsh-update-media-notice
new file mode 100644
index 0000000000000..69cc7c5cb8c32
--- /dev/null
+++ b/projects/plugins/wpcomsh/changelog/wpcomsh-update-media-notice
@@ -0,0 +1,4 @@
+Significance: patch
+Type: changed
+
+Media Library: don't show storage info on Atomic upload.php's uploader
diff --git a/projects/plugins/wpcomsh/custom-colors/colors.php b/projects/plugins/wpcomsh/custom-colors/colors.php
index b2a4405482e8d..15f56c8ee244c 100644
--- a/projects/plugins/wpcomsh/custom-colors/colors.php
+++ b/projects/plugins/wpcomsh/custom-colors/colors.php
@@ -1421,8 +1421,12 @@ public static function override_themecolors() {
$colors = $opts['colors'];
- $colors['border'] = $colors['fg1'];
- $colors['url'] = $colors['link'];
+ if ( isset( $colors['fg1'] ) ) {
+ $colors['border'] = $colors['fg1'];
+ }
+ if ( isset( $colors['link'] ) ) {
+ $colors['url'] = $colors['link'];
+ }
if ( isset( $colors['txt'] ) ) {
$colors['text'] = $colors['txt'];
}
diff --git a/projects/plugins/wpcomsh/notices/storage-notices.php b/projects/plugins/wpcomsh/notices/storage-notices.php
index 8ceeb3297c3b3..09ee42a365989 100644
--- a/projects/plugins/wpcomsh/notices/storage-notices.php
+++ b/projects/plugins/wpcomsh/notices/storage-notices.php
@@ -59,9 +59,15 @@ function wpcomsh_storage_notices() {
add_action( 'admin_notices', 'wpcomsh_storage_notices' );
/**
- * Display disk space usage on /wp-admin/upload.php
+ * Display disk space usage on the uploader
*/
function wpcomsh_display_disk_space_usage() {
+ global $pagenow;
+
+ if ( $pagenow === 'upload.php' ) {
+ return;
+ }
+
$site_info = wpcomsh_get_at_site_info();
if ( empty( $site_info['space_used'] ) || empty( $site_info['space_quota'] ) ) {