From 347017a1ebd95d7fb8ba7a1d27c6a894bb832a82 Mon Sep 17 00:00:00 2001
From: Erick Danzer
Date: Thu, 6 Feb 2025 12:52:03 -0700
Subject: [PATCH 01/19] Forms: fix invalid field ids (#41564)
---
.../forms/changelog/fix-invalid-field-ids | 4 +++
.../contact-form/class-contact-form-field.php | 26 ++++++++++++++++---
.../jetpack/changelog/fix-invalid-field-ids | 4 +++
3 files changed, 30 insertions(+), 4 deletions(-)
create mode 100644 projects/packages/forms/changelog/fix-invalid-field-ids
create mode 100644 projects/plugins/jetpack/changelog/fix-invalid-field-ids
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/contact-form/class-contact-form-field.php b/projects/packages/forms/src/contact-form/class-contact-form-field.php
index 52e5f6385e6e6..85b78314041eb 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 .= "
Date: Thu, 6 Feb 2025 12:00:51 -0800
Subject: [PATCH 02/19] Forms: Fix form submissions across pages that have
pagination applied (#41407)
* Forms: Add new page support for forms
This Pr adds support for form processing across multiple pages
* changelog
* sanitize with absint instead of sanitize_text_field
* guard against invalid $postdata
* Store entry_page and use in in there permalink
* Consoludate all the non printable fields
---
.../changelog/fix-form-submit-miulti-page | 4 ++
...class-wpcom-rest-api-v2-endpoint-forms.php | 8 +---
.../forms/src/contact-form/class-admin.php | 15 ++++---
.../class-contact-form-plugin.php | 26 ++++++++++++-
.../src/contact-form/class-contact-form.php | 39 +++++++++++++++----
.../changelog/fix-form-submit-miulti-page | 4 ++
6 files changed, 72 insertions(+), 24 deletions(-)
create mode 100644 projects/packages/forms/changelog/fix-form-submit-miulti-page
create mode 100644 projects/plugins/jetpack/changelog/fix-form-submit-miulti-page
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/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-plugin.php b/projects/packages/forms/src/contact-form/class-contact-form-plugin.php
index dc493a171a08f..b022a52e2a67c 100644
--- a/projects/packages/forms/src/contact-form/class-contact-form-plugin.php
+++ b/projects/packages/forms/src/contact-form/class-contact-form-plugin.php
@@ -52,6 +52,20 @@ class Contact_Form_Plugin {
*/
private $pde_email_address = '';
+ /*
+ * Field keys that might be present in the entry json but we don't want to show to the admin
+ * since they not something that the visitor entered into the form.
+ *
+ * @var array
+ */
+ const NON_PRINTABLE_FIELDS = array(
+ 'entry_title' => '',
+ '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/plugins/jetpack/changelog/fix-form-submit-miulti-page b/projects/plugins/jetpack/changelog/fix-form-submit-miulti-page
new file mode 100644
index 0000000000000..444f11caf4071
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/fix-form-submit-miulti-page
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+ Forms: Add support for having multiple forms accross paginated pages.
From da84905ffde1b168a46afce4f53d298a7d03cb34 Mon Sep 17 00:00:00 2001
From: Enej Bajgoric
Date: Thu, 6 Feb 2025 12:01:16 -0800
Subject: [PATCH 03/19] Forms: fix seperators not aligning consistently
(#40967)
* Fix: seperator block styling in the form block
* changelog
* Make the seperator earier to overwrite
* Fix the different styles to have the desired width.
* Remove any vertical margin
* Update projects/packages/forms/changelog/fix-25025-form-seperator
Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
* Update projects/plugins/jetpack/changelog/fix-25025-form-seperator
Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
* Remove the is-style-default class
* update to code to be more together.
* Update to use 100px vs 150px since that is the most common default saparator
* Also inherit the styles in the editor
* bug fix
---------
Co-authored-by: Miguel Lezama
Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
---
.../packages/forms/changelog/fix-25025-form-seperator | 4 ++++
.../forms/src/blocks/contact-form/editor.scss | 11 +++++++++++
.../packages/forms/src/contact-form/css/grunion.css | 10 ++++++++++
.../jetpack/changelog/fix-25025-form-seperator | 4 ++++
4 files changed, 29 insertions(+)
create mode 100644 projects/packages/forms/changelog/fix-25025-form-seperator
create mode 100644 projects/plugins/jetpack/changelog/fix-25025-form-seperator
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/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/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/plugins/jetpack/changelog/fix-25025-form-seperator b/projects/plugins/jetpack/changelog/fix-25025-form-seperator
new file mode 100644
index 0000000000000..9814b5a45b694
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/fix-25025-form-seperator
@@ -0,0 +1,4 @@
+Significance: patch
+Type: bugfix
+
+Forms: Improve the styling of the separator block when placed inside the form block
From 4b4b4e32aea893b5847f1a4cc71d274dd493631a Mon Sep 17 00:00:00 2001
From: Enej Bajgoric
Date: Thu, 6 Feb 2025 12:01:39 -0800
Subject: [PATCH 04/19] Forms: Fixes date validation bug (#41611)
* Forms: Fix the formatting if we use multiple date pickers on the page.
* Forms: No need to enqueue the localize jquery ui since it gets loaded anyways.
* changelog
---
.../forms/changelog/fix-date-validation-bug | 4 ++++
.../contact-form/class-contact-form-field.php | 2 --
.../src/contact-form/js/grunion-frontend.js | 20 ++++++++++---------
3 files changed, 15 insertions(+), 11 deletions(-)
create mode 100644 projects/packages/forms/changelog/fix-date-validation-bug
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/src/contact-form/class-contact-form-field.php b/projects/packages/forms/src/contact-form/class-contact-form-field.php
index 85b78314041eb..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
@@ -907,8 +907,6 @@ public function render_date_field( $id, $label, $value, $class, $required, $requ
wp_enqueue_style( 'jp-jquery-ui-datepicker', plugins_url( '../../dist/contact-form/css/jquery-ui-datepicker.css', __FILE__ ), array( 'dashicons' ), '1.0' );
- // Using Core's built-in datepicker localization routine
- wp_localize_jquery_ui_datepicker();
return $field;
}
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();
+ },
+ } );
} );
} );
From a8e7c90ab112e7278941e765fd2880a5e86c8745 Mon Sep 17 00:00:00 2001
From: Dylan Munson <65001528+CodeyGuyDylan@users.noreply.github.com>
Date: Thu, 6 Feb 2025 13:05:57 -0700
Subject: [PATCH 05/19] Fix my jetpack protect card shield inconsistency
(#41560)
* Show Protect WAF as disabled when firewall is disabled
* changelog
* Ensure variable is defined
---
.../protect-card/auto-firewall-status.tsx | 5 +++--
.../protect-card/use-protect-tooltip-copy.ts | 3 ++-
.../fix-my-jetpack-protect-card-shield-inconsistency | 4 ++++
projects/packages/my-jetpack/global.d.ts | 1 +
.../packages/my-jetpack/src/class-initializer.php | 11 +++++++----
5 files changed, 17 insertions(+), 7 deletions(-)
create mode 100644 projects/packages/my-jetpack/changelog/fix-my-jetpack-protect-card-shield-inconsistency
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 ) )
),
From 6ba505ac680148f67d0c5022d28f3b790ff65d18 Mon Sep 17 00:00:00 2001
From: Christian Gastrell
Date: Thu, 6 Feb 2025 18:20:15 -0300
Subject: [PATCH 06/19] Jetpack SEO: fix assistant chat options (#41616)
* fix and compensate spacings/gaps on step messages
* changelog
---
.../fix-jetpack-seo-assistant-chat-spacings | 4 +++
.../components/seo-assistant/style.scss | 27 +++++++++++++++++--
.../seo-assistant/wizard-messages.tsx | 1 +
3 files changed, 30 insertions(+), 2 deletions(-)
create mode 100644 projects/plugins/jetpack/changelog/fix-jetpack-seo-assistant-chat-spacings
diff --git a/projects/plugins/jetpack/changelog/fix-jetpack-seo-assistant-chat-spacings b/projects/plugins/jetpack/changelog/fix-jetpack-seo-assistant-chat-spacings
new file mode 100644
index 0000000000000..c0b75e32269f6
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/fix-jetpack-seo-assistant-chat-spacings
@@ -0,0 +1,4 @@
+Significance: patch
+Type: other
+
+Jetpack SEO: fix gap/spacing between chat bubbles and options
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 0acaea3025d52..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
@@ -63,6 +63,7 @@
&__content {
flex: 1 1 auto;
+ gap: 8px;
display: flex;
flex-direction: column;
height: 100%;
@@ -78,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 {
@@ -94,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;
@@ -122,6 +141,10 @@
display: none;
}
}
+
+ &.is-option {
+ align-self: flex-start;
+ }
}
&__input-container {
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 } ) =>
From 4f69df25b286d8198486c803c42a03a76d8c78d5 Mon Sep 17 00:00:00 2001
From: Luis Felipe Zaguini <26530524+zaguiini@users.noreply.github.com>
Date: Thu, 6 Feb 2025 18:45:15 -0300
Subject: [PATCH 07/19] Post actions: Rename "Copy" to "Duplicate" (#34844)
* Post actions: rename Copy action to Duplicate
* Add CHANGELOG entry
* Fix syntax issue added during merge conflict resolution
---------
Co-authored-by: Brandon Kraft
---
.../jetpack/changelog/enhance-rename-copy-post-duplicate | 4 ++++
projects/plugins/jetpack/modules/copy-post.php | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
create mode 100644 projects/plugins/jetpack/changelog/enhance-rename-copy-post-duplicate
diff --git a/projects/plugins/jetpack/changelog/enhance-rename-copy-post-duplicate b/projects/plugins/jetpack/changelog/enhance-rename-copy-post-duplicate
new file mode 100644
index 0000000000000..bdf2dcf1ee879
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/enhance-rename-copy-post-duplicate
@@ -0,0 +1,4 @@
+Significance: patch
+Type: enhancement
+
+Post actions: rename Copy action to Duplicate, which is clearer
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()
),
);
From 0d94cb4d28b583c57e3be2660c50e2aee5ddb4cd Mon Sep 17 00:00:00 2001
From: Ashar Fuadi
Date: Fri, 7 Feb 2025 09:12:04 +0700
Subject: [PATCH 08/19] External Media: Add Import button in Media Library
(#41544)
---
.../feat-external-media-import-button | 4 +++
.../admin/external-media-import-button.js | 23 +++++++++++++++
.../admin/external-media-import-button.scss | 12 ++++++++
.../features/admin/external-media-import.php | 29 +++++++++++++++++++
.../packages/external-media/webpack.config.js | 4 +++
5 files changed, 72 insertions(+)
create mode 100644 projects/packages/external-media/changelog/feat-external-media-import-button
create mode 100644 projects/packages/external-media/src/features/admin/external-media-import-button.js
create mode 100644 projects/packages/external-media/src/features/admin/external-media-import-button.scss
diff --git a/projects/packages/external-media/changelog/feat-external-media-import-button b/projects/packages/external-media/changelog/feat-external-media-import-button
new file mode 100644
index 0000000000000..628b477a5f482
--- /dev/null
+++ b/projects/packages/external-media/changelog/feat-external-media-import-button
@@ -0,0 +1,4 @@
+Significance: minor
+Type: added
+
+External Media: Add Import button in Media Library
diff --git a/projects/packages/external-media/src/features/admin/external-media-import-button.js b/projects/packages/external-media/src/features/admin/external-media-import-button.js
new file mode 100644
index 0000000000000..c852b3c9ea88c
--- /dev/null
+++ b/projects/packages/external-media/src/features/admin/external-media-import-button.js
@@ -0,0 +1,23 @@
+import { __ } from '@wordpress/i18n';
+
+document.addEventListener( 'DOMContentLoaded', function () {
+ const addNewButton = document.querySelector( 'a.page-title-action' );
+ if ( addNewButton ) {
+ const buttonContainer = document.createElement( 'div' );
+ buttonContainer.className = 'wpcom-media-library-action-buttons';
+
+ const importButton = document.createElement( 'a' );
+ importButton.className = 'button';
+ importButton.role = 'button';
+ importButton.innerHTML = __( 'Import Media', 'jetpack-external-media' );
+ importButton.href = window.JETPACK_EXTERNAL_MEDIA_IMPORT_BUTTON?.href;
+
+ const parentNode = addNewButton.parentNode;
+ const nextSibling = addNewButton.nextSibling;
+
+ buttonContainer.appendChild( addNewButton );
+ buttonContainer.appendChild( importButton );
+
+ parentNode.insertBefore( buttonContainer, nextSibling );
+ }
+} );
diff --git a/projects/packages/external-media/src/features/admin/external-media-import-button.scss b/projects/packages/external-media/src/features/admin/external-media-import-button.scss
new file mode 100644
index 0000000000000..df9db337f0ab9
--- /dev/null
+++ b/projects/packages/external-media/src/features/admin/external-media-import-button.scss
@@ -0,0 +1,12 @@
+.wpcom-media-library-action-buttons {
+ display: inline-flex;
+ flex-wrap: wrap;
+ gap: 4px;
+
+ > a {
+ position: relative;
+ top: -3px;
+ margin-left: 0;
+ vertical-align: baseline;
+ }
+}
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/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,
From 048f9fb4379db1b33c22f2dc79bf1eab01f9be73 Mon Sep 17 00:00:00 2001
From: arthur791004
Date: Fri, 7 Feb 2025 10:46:46 +0800
Subject: [PATCH 09/19] External Media: Add track events to the Import page and
modal (#41592)
* External Media: Add track event to Import now button
* External Media: Add track event to Import media button
* changelog
---
.../feat-external-media-track-events | 4 +
.../features/admin/external-media-import.js | 7 +-
.../src/shared/media-browser/index.js | 80 ++++++++++---------
.../media-browser-select-button.js | 24 ++++++
.../shared/media-browser/use-page-source.js | 18 +++++
.../google-photos/google-photos-media.js | 2 +
.../shared/sources/jetpack-app-media/index.js | 1 +
.../src/shared/sources/openverse/index.js | 1 +
.../src/shared/sources/pexels/index.js | 1 +
9 files changed, 100 insertions(+), 38 deletions(-)
create mode 100644 projects/packages/external-media/changelog/feat-external-media-track-events
create mode 100644 projects/packages/external-media/src/shared/media-browser/media-browser-select-button.js
create mode 100644 projects/packages/external-media/src/shared/media-browser/use-page-source.js
diff --git a/projects/packages/external-media/changelog/feat-external-media-track-events b/projects/packages/external-media/changelog/feat-external-media-track-events
new file mode 100644
index 0000000000000..9c86bd2e0a665
--- /dev/null
+++ b/projects/packages/external-media/changelog/feat-external-media-track-events
@@ -0,0 +1,4 @@
+Significance: minor
+Type: added
+
+External Media: Add track events to the Import page and modal
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/shared/media-browser/index.js b/projects/packages/external-media/src/shared/media-browser/index.js
index e9bd6bd4551aa..3365e500f6a1c 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_cta_click', {
+ page_source: 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 (
-
-
- { label }
-
-
- );
+
+ 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 (
+
+
+ { label }
+
+
+ );
+};
+
+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..465bf48293ee4
--- /dev/null
+++ b/projects/packages/external-media/src/shared/media-browser/use-page-source.js
@@ -0,0 +1,18 @@
+import { useSelect } from '@wordpress/data';
+
+const usePageSource = () => {
+ const isSiteEditor = useSelect( select => !! select( 'core/edit-site' ), [] );
+ const postType = useSelect( select => select( 'core/editor' )?.getCurrentPostType(), [] );
+
+ if ( ! postType ) {
+ return 'jetpack-external-media-import-page';
+ }
+
+ if ( isSiteEditor ) {
+ return 'site-editor';
+ }
+
+ return postType === 'page' ? 'page-editor' : 'post-editor';
+};
+
+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 ) }
From 0831a4208eb5ff7279fa105ce1edec7f4ad8f165 Mon Sep 17 00:00:00 2001
From: Ashar Fuadi
Date: Fri, 7 Feb 2025 13:32:59 +0700
Subject: [PATCH 10/19] Media Library: add track events for upload from URL
feature (#41620)
---
.../packages/external-media/changelog/media-tracks | 4 ++++
.../src/shared/media-browser/index.js | 4 ++--
.../src/shared/media-browser/use-page-source.js | 14 ++++----------
.../jetpack-mu-wpcom/changelog/media-tracks | 4 ++++
.../wpcom-media-url-upload-form/index.jsx | 9 +++++++--
.../wpcom-media/wpcom-media-url-upload.php | 8 ++++----
6 files changed, 25 insertions(+), 18 deletions(-)
create mode 100644 projects/packages/external-media/changelog/media-tracks
create mode 100644 projects/packages/jetpack-mu-wpcom/changelog/media-tracks
diff --git a/projects/packages/external-media/changelog/media-tracks b/projects/packages/external-media/changelog/media-tracks
new file mode 100644
index 0000000000000..48205a668b670
--- /dev/null
+++ b/projects/packages/external-media/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/external-media/src/shared/media-browser/index.js b/projects/packages/external-media/src/shared/media-browser/index.js
index 3365e500f6a1c..7ba3619044401 100644
--- a/projects/packages/external-media/src/shared/media-browser/index.js
+++ b/projects/packages/external-media/src/shared/media-browser/index.js
@@ -72,8 +72,8 @@ function MediaBrowser( {
);
const onCopyAndInsert = useCallback( () => {
- tracks.recordEvent( 'jetpack_external_media_modal_cta_click', {
- page_source: pageSource,
+ tracks.recordEvent( 'jetpack_external_media_modal_submit', {
+ page: pageSource,
media_source: mediaSource,
media_count: selected.length,
multiple: !! multiple,
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
index 465bf48293ee4..70cfa13b6e7e6 100644
--- 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
@@ -1,18 +1,12 @@
import { useSelect } from '@wordpress/data';
const usePageSource = () => {
- const isSiteEditor = useSelect( select => !! select( 'core/edit-site' ), [] );
- const postType = useSelect( select => select( 'core/editor' )?.getCurrentPostType(), [] );
+ const isEditor = useSelect( select => !! select( 'core/editor' ), [] );
- if ( ! postType ) {
- return 'jetpack-external-media-import-page';
+ if ( isEditor ) {
+ return 'editor';
}
-
- if ( isSiteEditor ) {
- return 'site-editor';
- }
-
- return postType === 'page' ? 'page-editor' : 'post-editor';
+ return 'media-library';
};
export default usePageSource;
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',
)
);
From 60e22d6b826a4c80f81f2afcde94d013cec92e8d Mon Sep 17 00:00:00 2001
From: Juanma Rodriguez Escriche
Date: Fri, 7 Feb 2025 09:00:15 +0100
Subject: [PATCH 11/19] Update/dont sync set object terms action for
blacklisted taxonomies (#41597)
* Don't send term relationships for full sync posts actions since they are not being processed
* changelog
* Fixed next-version typo
* Remove test no longer valid
* changelog
---
...ct-terms-action-for-blacklisted-taxonomies | 4 ++++
.../packages/sync/src/modules/class-posts.php | 23 ++++++++++++++++++-
.../modules/class-woocommerce-hpos-orders.php | 2 +-
...ct-terms-action-for-blacklisted-taxonomies | 4 ++++
...st_class.jetpack-sync-full-immediately.php | 18 ---------------
5 files changed, 31 insertions(+), 20 deletions(-)
create mode 100644 projects/packages/sync/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
create mode 100644 projects/plugins/jetpack/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
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/jetpack/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies b/projects/plugins/jetpack/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
new file mode 100644
index 0000000000000..76e66c9980175
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/update-dont-sync-set-object-terms-action-for-blacklisted-taxonomies
@@ -0,0 +1,4 @@
+Significance: minor
+Type: other
+
+Sync: Full sync for posts not sending term relationships
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 );
From 71ea4c66fa785ad140dafbfbdf4c4492df7a3e15 Mon Sep 17 00:00:00 2001
From: Ashar Fuadi
Date: Fri, 7 Feb 2025 16:18:12 +0700
Subject: [PATCH 12/19] Media Library: don't show storage info on Atomic
upload.php's uploader (#41625)
---
.../plugins/wpcomsh/changelog/wpcomsh-update-media-notice | 4 ++++
projects/plugins/wpcomsh/notices/storage-notices.php | 8 +++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
create mode 100644 projects/plugins/wpcomsh/changelog/wpcomsh-update-media-notice
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/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'] ) ) {
From 00c4981cef6d782a3e9b67d124966ade92318827 Mon Sep 17 00:00:00 2001
From: Ashar Fuadi
Date: Fri, 7 Feb 2025 16:36:14 +0700
Subject: [PATCH 13/19] Media Library: add track event to the Import Media
button (#41626)
---
.../external-media/changelog/media-library-tracks-2 | 4 ++++
.../src/features/admin/external-media-import-button.js | 6 ++++++
2 files changed, 10 insertions(+)
create mode 100644 projects/packages/external-media/changelog/media-library-tracks-2
diff --git a/projects/packages/external-media/changelog/media-library-tracks-2 b/projects/packages/external-media/changelog/media-library-tracks-2
new file mode 100644
index 0000000000000..5c6cbae94d559
--- /dev/null
+++ b/projects/packages/external-media/changelog/media-library-tracks-2
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Media Library: add track event to the Import Media button
diff --git a/projects/packages/external-media/src/features/admin/external-media-import-button.js b/projects/packages/external-media/src/features/admin/external-media-import-button.js
index c852b3c9ea88c..22145691a40f7 100644
--- a/projects/packages/external-media/src/features/admin/external-media-import-button.js
+++ b/projects/packages/external-media/src/features/admin/external-media-import-button.js
@@ -1,3 +1,4 @@
+import jetpackAnalytics from '@automattic/jetpack-analytics';
import { __ } from '@wordpress/i18n';
document.addEventListener( 'DOMContentLoaded', function () {
@@ -11,6 +12,11 @@ document.addEventListener( 'DOMContentLoaded', function () {
importButton.role = 'button';
importButton.innerHTML = __( 'Import Media', 'jetpack-external-media' );
importButton.href = window.JETPACK_EXTERNAL_MEDIA_IMPORT_BUTTON?.href;
+ importButton.onclick = function () {
+ jetpackAnalytics.tracks.recordEvent( 'jetpack_external_media_import_media_button_click', {
+ page: 'media-library',
+ } );
+ };
const parentNode = addNewButton.parentNode;
const nextSibling = addNewButton.nextSibling;
From c7e6c1f572c83f1fad74e299a3cbeb9712df4c90 Mon Sep 17 00:00:00 2001
From: Kolja Zuelsdorf
Date: Fri, 7 Feb 2025 11:43:05 +0100
Subject: [PATCH 14/19] Added a debug tool to send API requests to WPcom via
the Jetpack connection. (#41154)
* Added a debug tool to send API requests to WPcom via the Jetpack connection. This is to help with testing singular API requests that are in development and supposed to be called by Jetpack over the connection.
* Added changelog.
* Ensured that the connection classes actually exist (so that a helper can be set up) before using this helper. Moved module initialization to static method, so we don't have an empty object to construct.
* Update phan baseline.
* Update phan baseline.
* Don't add extra IP for public API.
* Extended request faker to allow different HTTP methods other than GET.
---
.../plugins/debug-helper/.phan/baseline.php | 1 +
.../debug-add-wpcom-api-request-faker | 4 +
.../class-wpcom-api-request-faker-module.php | 185 ++++++++++++++++++
projects/plugins/debug-helper/plugin.php | 5 +
4 files changed, 195 insertions(+)
create mode 100644 projects/plugins/debug-helper/changelog/debug-add-wpcom-api-request-faker
create mode 100644 projects/plugins/debug-helper/modules/class-wpcom-api-request-faker-module.php
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',
From 3c6ee841f63609aa260915ee3e496b0429cff2aa Mon Sep 17 00:00:00 2001
From: Jorge Costa
Date: Fri, 7 Feb 2025 11:30:10 +0000
Subject: [PATCH 15/19] Fix: Warnings on any theme using customizer colors.
(#41136)
* Fix: Warnings on any theme using customizer colors.
* changelog
---
.../fix-warnings-on-any-theme-using-customizer-colors | 4 ++++
projects/plugins/wpcomsh/custom-colors/colors.php | 8 ++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
create mode 100644 projects/plugins/wpcomsh/changelog/fix-warnings-on-any-theme-using-customizer-colors
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/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'];
}
From 5fee730852dca90864477a58d1d6435ffd82813c Mon Sep 17 00:00:00 2001
From: Peter Petrov
Date: Fri, 7 Feb 2025 14:33:34 +0200
Subject: [PATCH 16/19] Boost: Add compatibility with Depay Payments for
WooCommerce (#41571)
---
.../boost/changelog/fix-boost-compatibility-depay-woocommerce | 4 ++++
projects/plugins/boost/compatibility/js-concatenate.php | 2 ++
2 files changed, 6 insertions(+)
create mode 100644 projects/plugins/boost/changelog/fix-boost-compatibility-depay-woocommerce
diff --git a/projects/plugins/boost/changelog/fix-boost-compatibility-depay-woocommerce b/projects/plugins/boost/changelog/fix-boost-compatibility-depay-woocommerce
new file mode 100644
index 0000000000000..6044234689c32
--- /dev/null
+++ b/projects/plugins/boost/changelog/fix-boost-compatibility-depay-woocommerce
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Concatenate JS: Add compatibility with "Depay Payments for WooCommerce".
diff --git a/projects/plugins/boost/compatibility/js-concatenate.php b/projects/plugins/boost/compatibility/js-concatenate.php
index b4aca14772b45..0e3157c94860c 100644
--- a/projects/plugins/boost/compatibility/js-concatenate.php
+++ b/projects/plugins/boost/compatibility/js-concatenate.php
@@ -12,6 +12,8 @@ function maybe_do_not_concat( $do_concat, $handle ) {
'tribe-tickets-provider',
// Plugin: `woocommerce-shipping`
'woocommerce-shipping-checkout-address-validation',
+ // Plugin: `depay-payments-for-woocommerce`
+ 'DEPAY_WC_WIDGETS',
);
if ( in_array( $handle, $excluded_handles, true ) ) {
From 276eb079afd00c26b544ad4be416fa5cb87341e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Donncha=20=C3=93=20Caoimh?=
<5656673+donnchawp@users.noreply.github.com>
Date: Fri, 7 Feb 2025 13:06:50 +0000
Subject: [PATCH 17/19] Boost: Run the 404 tester when concatenate modules are
enabled (#41593)
---
.../app/lib/minify/functions-service.php | 15 ++-
.../optimizations/minify/class-minify-css.php | 7 +-
.../optimizations/minify/class-minify-js.php | 7 +-
.../changelog/update-boost-404-test-activate | 5 +
.../php/lib/minify/test-functions-service.php | 99 +++++++++++++++++++
5 files changed, 128 insertions(+), 5 deletions(-)
create mode 100644 projects/plugins/boost/changelog/update-boost-404-test-activate
create mode 100644 projects/plugins/boost/tests/php/lib/minify/test-functions-service.php
diff --git a/projects/plugins/boost/app/lib/minify/functions-service.php b/projects/plugins/boost/app/lib/minify/functions-service.php
index 798e986d6fad0..ccdf9e8513a06 100644
--- a/projects/plugins/boost/app/lib/minify/functions-service.php
+++ b/projects/plugins/boost/app/lib/minify/functions-service.php
@@ -68,17 +68,26 @@ function jetpack_boost_check_404_handler( $request_uri ) {
* This function is used to test if is_404() is working in wp-content/
* It sends a request to a non-existent URL, that will execute the 404 handler
* in jetpack_boost_check_404_handler().
+ * Define the constant JETPACK_BOOST_DISABLE_404_TESTER to disable this.
*
- * This function is called when the Minify_CSS or Minify_JS module is activated.
+ * This function is called when the Minify_CSS or Minify_JS module is activated, and once per day.
*/
function jetpack_boost_404_tester() {
+ if ( defined( 'JETPACK_BOOST_DISABLE_404_TESTER' ) && JETPACK_BOOST_DISABLE_404_TESTER ) {
+ return;
+ }
+
+ $minification_enabled = '';
wp_remote_get( home_url( '/wp-content/boost-cache/static/testing_404' ) );
if ( file_exists( Config::get_static_cache_dir_path() . '/404' ) ) {
wp_delete_file( Config::get_static_cache_dir_path() . '/404' );
- update_site_option( 'jetpack_boost_static_minification', 1 );
+ $minification_enabled = 1;
} else {
- update_site_option( 'jetpack_boost_static_minification', 0 );
+ $minification_enabled = 0;
}
+ update_site_option( 'jetpack_boost_static_minification', $minification_enabled );
+
+ return $minification_enabled;
}
add_action( 'jetpack_boost_404_tester_cron', 'jetpack_boost_404_tester' );
diff --git a/projects/plugins/boost/app/modules/optimizations/minify/class-minify-css.php b/projects/plugins/boost/app/modules/optimizations/minify/class-minify-css.php
index 2144a5072c269..efeec1c0ac79f 100644
--- a/projects/plugins/boost/app/modules/optimizations/minify/class-minify-css.php
+++ b/projects/plugins/boost/app/modules/optimizations/minify/class-minify-css.php
@@ -3,12 +3,13 @@
namespace Automattic\Jetpack_Boost\Modules\Optimizations\Minify;
use Automattic\Jetpack_Boost\Contracts\Changes_Page_Output;
+use Automattic\Jetpack_Boost\Contracts\Has_Activate;
use Automattic\Jetpack_Boost\Contracts\Has_Deactivate;
use Automattic\Jetpack_Boost\Contracts\Optimization;
use Automattic\Jetpack_Boost\Contracts\Pluggable;
use Automattic\Jetpack_Boost\Lib\Minify\Concatenate_CSS;
-class Minify_CSS implements Pluggable, Changes_Page_Output, Optimization, Has_Deactivate {
+class Minify_CSS implements Pluggable, Changes_Page_Output, Optimization, Has_Activate, Has_Deactivate {
public static $default_excludes = array( 'admin-bar', 'dashicons', 'elementor-app' );
@@ -49,6 +50,10 @@ public function init_minify() {
$wp_styles->allow_gzip_compression = true; // @todo - used constant ALLOW_GZIP_COMPRESSION = true if not defined.
}
+ public static function activate() {
+ jetpack_boost_404_tester();
+ }
+
public static function deactivate() {
jetpack_boost_page_optimize_cleanup_cache( 'css' );
}
diff --git a/projects/plugins/boost/app/modules/optimizations/minify/class-minify-js.php b/projects/plugins/boost/app/modules/optimizations/minify/class-minify-js.php
index 0a9bfb319a011..76998a6c4e824 100644
--- a/projects/plugins/boost/app/modules/optimizations/minify/class-minify-js.php
+++ b/projects/plugins/boost/app/modules/optimizations/minify/class-minify-js.php
@@ -3,12 +3,13 @@
namespace Automattic\Jetpack_Boost\Modules\Optimizations\Minify;
use Automattic\Jetpack_Boost\Contracts\Changes_Page_Output;
+use Automattic\Jetpack_Boost\Contracts\Has_Activate;
use Automattic\Jetpack_Boost\Contracts\Has_Deactivate;
use Automattic\Jetpack_Boost\Contracts\Optimization;
use Automattic\Jetpack_Boost\Contracts\Pluggable;
use Automattic\Jetpack_Boost\Lib\Minify\Concatenate_JS;
-class Minify_JS implements Pluggable, Changes_Page_Output, Optimization, Has_Deactivate {
+class Minify_JS implements Pluggable, Changes_Page_Output, Optimization, Has_Activate, Has_Deactivate {
public static $default_excludes = array( 'jquery', 'jquery-core', 'underscore', 'backbone' );
@@ -49,6 +50,10 @@ public function init_minify() {
$wp_scripts->allow_gzip_compression = true; // @todo - used constant ALLOW_GZIP_COMPRESSION = true if not defined.
}
+ public static function activate() {
+ jetpack_boost_404_tester();
+ }
+
public static function deactivate() {
jetpack_boost_page_optimize_cleanup_cache( 'js' );
}
diff --git a/projects/plugins/boost/changelog/update-boost-404-test-activate b/projects/plugins/boost/changelog/update-boost-404-test-activate
new file mode 100644
index 0000000000000..535387eb3008f
--- /dev/null
+++ b/projects/plugins/boost/changelog/update-boost-404-test-activate
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fixed
+Comment: Minification: run the 404 tester when activating either of the minification/concatenation modules.
+
+
diff --git a/projects/plugins/boost/tests/php/lib/minify/test-functions-service.php b/projects/plugins/boost/tests/php/lib/minify/test-functions-service.php
new file mode 100644
index 0000000000000..2cf2d253b4f5b
--- /dev/null
+++ b/projects/plugins/boost/tests/php/lib/minify/test-functions-service.php
@@ -0,0 +1,99 @@
+andReturn( true );
+
+ // Clean up any test files before each test
+ if ( file_exists( Config::get_static_cache_dir_path() . '/404' ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_exists
+ unlink( Config::get_static_cache_dir_path() . '/404' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
+ }
+ require_once __DIR__ . '/../../../../app/lib/minify/loader.php';
+ }
+
+ public function test_404_tester_when_404_file_exists() {
+ // Create mock 404 file
+ $cache_dir = Config::get_static_cache_dir_path();
+ if ( ! is_dir( $cache_dir ) ) {
+ mkdir( $cache_dir, 0775, true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
+ }
+ file_put_contents( $cache_dir . '/404', '1' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
+
+ Functions\expect( 'home_url' )
+ ->once()
+ ->with( '/wp-content/boost-cache/static/testing_404' )
+ ->andReturn( 'http://example.com/wp-content/boost-cache/static/testing_404' );
+
+ Functions\expect( 'wp_remote_get' )
+ ->once()
+ ->with( 'http://example.com/wp-content/boost-cache/static/testing_404' );
+
+ Functions\expect( 'wp_delete_file' )
+ ->once()
+ ->with( $cache_dir . '/404' );
+
+ Functions\expect( 'update_site_option' )
+ ->once()
+ ->with( 'jetpack_boost_static_minification', 1 );
+
+ $this->assertEquals( 1, jetpack_boost_404_tester() );
+ }
+
+ public function test_404_tester_when_404_file_does_not_exist() {
+ Functions\expect( 'home_url' )
+ ->once()
+ ->with( '/wp-content/boost-cache/static/testing_404' )
+ ->andReturn( 'http://example.com/wp-content/boost-cache/static/testing_404' );
+
+ Functions\expect( 'wp_remote_get' )
+ ->once()
+ ->with( 'http://example.com/wp-content/boost-cache/static/testing_404' );
+
+ Functions\expect( 'update_site_option' )
+ ->once()
+ ->with( 'jetpack_boost_static_minification', 0 );
+
+ $this->assertEquals( 0, jetpack_boost_404_tester() );
+ }
+
+ public function test_404_tester_disabled_by_constant() {
+ if ( ! defined( 'JETPACK_BOOST_DISABLE_404_TESTER' ) ) {
+ define( 'JETPACK_BOOST_DISABLE_404_TESTER', true );
+ }
+
+ Functions\expect( 'wp_remote_get' )->never();
+ Functions\expect( 'update_site_option' )->never();
+
+ $this->assertEquals( '', jetpack_boost_404_tester() );
+ }
+
+ protected function tear_down() {
+ parent::tear_down();
+
+ // Clean up any test files after each test
+ if ( file_exists( Config::get_static_cache_dir_path() . '/404' ) ) {
+ unlink( Config::get_static_cache_dir_path() . '/404' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
+ }
+
+ $path = '/tmp/wordpress/wp-content/boost-cache/static/';
+ while ( $path !== '/tmp' ) {
+ if ( is_dir( $path ) ) {
+ rmdir( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir
+ }
+ $path = dirname( $path );
+ }
+ }
+}
From e33f0ecea8268c1f19c47e5db57fc5e2d41b71ad Mon Sep 17 00:00:00 2001
From: Igor Zinovyev
Date: Fri, 7 Feb 2025 16:38:10 +0300
Subject: [PATCH 18/19] Removed p tags and added whitespace instead. (#41633)
---
tools/cli/helpers/doc-parser/src/class-doc-parser.php | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/tools/cli/helpers/doc-parser/src/class-doc-parser.php b/tools/cli/helpers/doc-parser/src/class-doc-parser.php
index f4014d0cdff8c..83d7002d6b79d 100644
--- a/tools/cli/helpers/doc-parser/src/class-doc-parser.php
+++ b/tools/cli/helpers/doc-parser/src/class-doc-parser.php
@@ -243,9 +243,7 @@ function ( Node $node ) {
if ( ! empty( $entry->text ) ) {
$block['doc']['description'] .=
- ''
- . str_replace( array( "\r\n", "\n", "\r" ), '
', $entry->text )
- . '
';
+ str_replace( array( "\r\n", "\n", "\r" ), ' ', $entry->text );
}
}
From f2c86e0a0dd77dcda03dc2e75bf7b5b0aab81af0 Mon Sep 17 00:00:00 2001
From: Igor Zinovyev
Date: Fri, 7 Feb 2025 16:46:03 +0300
Subject: [PATCH 19/19] Add a safeguard for Sharing post filter results.
(#41600)
* Added a safeguard for the post object in Sharing.
* changelog
* Moved the check upwards and changed it to instance detection, h/t @jeherve.
* Removed accidental duplication.
---
projects/plugins/jetpack/changelog/add-sharing-safeguard-post | 4 ++++
.../plugins/jetpack/modules/sharedaddy/sharing-service.php | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
create mode 100644 projects/plugins/jetpack/changelog/add-sharing-safeguard-post
diff --git a/projects/plugins/jetpack/changelog/add-sharing-safeguard-post b/projects/plugins/jetpack/changelog/add-sharing-safeguard-post
new file mode 100644
index 0000000000000..c8ba163b65325
--- /dev/null
+++ b/projects/plugins/jetpack/changelog/add-sharing-safeguard-post
@@ -0,0 +1,4 @@
+Significance: patch
+Type: bugfix
+
+Sharing: Fix possible warnings related to plugin compatibility.
diff --git a/projects/plugins/jetpack/modules/sharedaddy/sharing-service.php b/projects/plugins/jetpack/modules/sharedaddy/sharing-service.php
index db9a37dac1216..d726ec387adc3 100644
--- a/projects/plugins/jetpack/modules/sharedaddy/sharing-service.php
+++ b/projects/plugins/jetpack/modules/sharedaddy/sharing-service.php
@@ -960,7 +960,8 @@ function sharing_display( $text = '', $echo = false ) {
return $text;
}
- if ( empty( $post ) ) {
+ // We require the post to not be empty and be an actual WordPress post object. If it's not - we just return.
+ if ( empty( $post ) || ! $post instanceof \WP_Post ) {
return $text;
}