Repository: Automattic/wp-calypso
Pull request #103360: Fix warning notices for Publicize incomplete connection
Author: login: aduth
Labels: name: Bug
description: When a feature is broken and / or not performing as intended
name: Publicize
Created: 2025-05-12T19:01:50Z | Merged: 2025-05-15T16:32:12Z

<!--
Link a related Github/Linear issue to this PR. If the PR does not immediately resolve the issue,
for example, it requires a separate deployment to production, avoid
using the "fixes" keyword. Consider using "part of" instead.
-->

Related to: https://github.com/Automattic/wp-calypso/pull/103138#discussion_r2081963646

## Proposed Changes

* Fixes alert notices that were intended to be shown when a Publicize connection could not be made

As discovered in #103138, the connected actions associated with failed Publicize connections were not actually connected to anything. The changes here fix this by dispatching the equivalent notice actions, removing the unused `failCreateConnection` action creator in the process.

## Why are these changes being made?
<!--
It's easy to see what a PR does but much harder to find out why it was made,
particularly when researching old changes in history. Record an explanation of
the motivation behind this change and how it will help.
-->

* So users can be informed when a connection could not be made
* Reduce code size by leveraging existing functionality for alerting

## Testing Instructions

<!--
Add as many details as possible to help others reproduce the issue and test the fix.
"Before / After" screenshots can also be very helpful when the change is visual.
-->

Verify notices are shown for affected services when the connection is incomplete:

1. Go to http://calypso.localhost:3000/marketing/connections
2. Pick a site
3. Click "Connect" next to one of the services
4. Close the popup
5. Observe that you see an alert notice

Example:

![image](https://github.com/user-attachments/assets/c8f9a499-7b9a-478a-9d38-1e88407763ae)

## Pre-merge Checklist

<!--
Complete applicable items on this checklist **before** merging into trunk. Inapplicable items can be left unchecked.

Both the PR author and reviewer are responsible for ensuring the checklist is completed.
-->

- [ ] Has the general commit checklist been followed? (PCYsg-hS-p2)
- [ ] [Have you written new tests](https://wpcalypso.wordpress.com/devdocs/docs/testing/index.md) for your changes?
- [ ] Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
- [ ] Have you checked for TypeScript, React or other console errors?
- [ ] Have you used memoizing on expensive computations? More info in [Memoizing with create-selector](https://github.com/Automattic/wp-calypso/blob/trunk/packages/state-utils/src/create-selector/README.md) and [Using memoizing selectors](https://react-redux.js.org/api/hooks#using-memoizing-selectors) and [Our Approach to Data](https://github.com/Automattic/wp-calypso/blob/trunk/docs/our-approach-to-data.md)
- [ ] Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
    - [ ] For UI changes, have we tested the change in various languages (for example, ES, PT, FR, or DE)? The length of text and words vary significantly between languages. 
- [ ] For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?



Diff:
diff --git a/client/sites/marketing/connections/service.jsx b/client/sites/marketing/connections/service.jsx
index 189784de8b5e..b38a4cc22d88 100644
--- a/client/sites/marketing/connections/service.jsx
+++ b/client/sites/marketing/connections/service.jsx
@@ -29,7 +29,6 @@ import {
 import {
 	createSiteConnection,
 	deleteSiteConnection,
-	failCreateConnection,
 	fetchConnection,
 	updateSiteConnection,
 } from 'calypso/state/sharing/publicize/actions';
@@ -66,7 +65,6 @@ export class SharingService extends Component {
 		createSiteConnection: PropTypes.func,
 		deleteSiteConnection: PropTypes.func,
 		errorNotice: PropTypes.func,
-		failCreateConnection: PropTypes.func,
 		fetchConnection: PropTypes.func,
 		isFetching: PropTypes.bool,
 		keyringConnections: PropTypes.arrayOf( PropTypes.object ),
@@ -91,7 +89,6 @@ export class SharingService extends Component {
 		createSiteConnection: () => {},
 		deleteSiteConnection: () => {},
 		errorNotice: () => {},
-		failCreateConnection: () => {},
 		fetchConnection: () => {},
 		isFetching: false,
 		keyringConnections: [],
@@ -450,27 +447,29 @@ export class SharingService extends Component {
 			// At this point, if there are no available accounts to
 			// select, we must assume the user closed the popup
 			// before completing the authorization step.
-			this.props.failCreateConnection( {
-				message: this.props.translate(
+			this.props.warningNotice(
+				this.props.translate(
 					'The %(service)s connection could not be made because no account was selected.',
 					{
 						args: { service: this.props.service.label },
 						context: 'Sharing: Publicize connection confirmation',
 					}
 				),
-			} );
+				{ id: 'publicize' }
+			);
 			this.setState( { isConnecting: false } );
 		} else if ( ! hasAnyConnectionOptions ) {
 			// Similarly warn user if all options are connected
-			this.props.failCreateConnection( {
-				message: this.props.translate(
+			this.props.warningNotice(
+				this.props.translate(
 					'The %(service)s connection could not be made because all available accounts are already connected.',
 					{
 						args: { service: this.props.service.label },
 						context: 'Sharing: Publicize connection confirmation',
 					}
 				),
-			} );
+				{ id: 'publicize' }
+			);
 			this.setState( { isConnecting: false } );
 		}
 		this.setState( { justConnected: true } );
@@ -753,7 +752,6 @@ export function connectFor( sharingService, mapStateToProps, mapDispatchToProps
 			deleteSiteConnection,
 			successNotice,
 			errorNotice,
-			failCreateConnection,
 			fetchConnection,
 			recordGoogleEvent,
 			recordTracksEvent,
diff --git a/client/sites/marketing/connections/services/facebook.js b/client/sites/marketing/connections/services/facebook.js
index 69850a822f01..6b7b174831af 100644
--- a/client/sites/marketing/connections/services/facebook.js
+++ b/client/sites/marketing/connections/services/facebook.js
@@ -14,35 +14,32 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
+			this.props.warningNotice(
+				<>
+					{ this.props.translate(
 						'The Facebook connection could not be made because this account does not have access to any Pages.',
 						{
 							context: 'Sharing: Jetpack Social connection error',
 						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
+					) }{ ' ' }
+					{ this.props.translate(
 						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
 							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
 						{
 							components: {
 								a: (
 									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
+										href={ localizeUrl( 'https://wordpress.com/support/post-to-facebook/' ) }
 										target="_blank"
 										rel="noopener noreferrer"
 									/>
 								),
 							},
 						}
-					),
-				],
-			} );
+					) }
+				</>,
+				{ id: 'publicize' }
+			);
 			this.setState( { isConnecting: false } );
 			return false;
 		}
diff --git a/client/sites/marketing/connections/services/google-drive.js b/client/sites/marketing/connections/services/google-drive.js
index 3014259650b3..530d64960d7d 100644
--- a/client/sites/marketing/connections/services/google-drive.js
+++ b/client/sites/marketing/connections/services/google-drive.js
@@ -27,15 +27,12 @@ export class GoogleDrive extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate( 'The Google Drive connection could not be made.', {
-						context: 'Sharing: Jetpack Social connection error',
-					} ),
-					' ',
-					' ',
-				],
-			} );
+			this.props.warningNotice(
+				this.props.translate( 'The Google Drive connection could not be made.', {
+					context: 'Sharing: Jetpack Social connection error',
+				} ),
+				{ id: 'publicize' }
+			);
 			this.setState( { isConnecting: false } );
 			return false;
 		}
diff --git a/client/sites/marketing/connections/services/google-my-business.js b/client/sites/marketing/connections/services/google-my-business.js
index 488b8c849389..1ad9b233a90e 100644
--- a/client/sites/marketing/connections/services/google-my-business.js
+++ b/client/sites/marketing/connections/services/google-my-business.js
@@ -45,11 +45,12 @@ export class GoogleMyBusiness extends SharingService {
 		this.props
 			.connectGoogleMyBusinessLocation( this.props.siteId, keyringConnectionId, externalUserId )
 			.catch( () => {
-				this.props.failCreateConnection( {
-					message: this.props.translate( 'Error while linking your site to %(service)s.', {
+				this.props.warningNotice(
+					this.props.translate( 'Error while linking your site to %(service)s.', {
 						args: { service: this.props.service.label },
 					} ),
-				} );
+					{ id: 'publicize' }
+				);
 			} )
 			.finally( () => {
 				this.setState( { isConnecting: false } );
diff --git a/client/state/action-types.ts b/client/state/action-types.ts
index f94d07bd7560..375e91cba514 100644
--- a/client/state/action-types.ts
+++ b/client/state/action-types.ts
@@ -713,7 +713,6 @@ export const PRODUCTS_LIST_RECEIVE = 'PRODUCTS_LIST_RECEIVE';
 export const PRODUCTS_LIST_REQUEST = 'PRODUCTS_LIST_REQUEST';
 export const PRODUCTS_LIST_REQUEST_FAILURE = 'PRODUCTS_LIST_REQUEST_FAILURE';
 export const PUBLICIZE_CONNECTION_CREATE = 'PUBLICIZE_CONNECTION_CREATE';
-export const PUBLICIZE_CONNECTION_CREATE_FAILURE = 'PUBLICIZE_CONNECTION_CREATE_FAILURE';
 export const PUBLICIZE_CONNECTION_DELETE = 'PUBLICIZE_CONNECTION_DELETE';
 export const PUBLICIZE_CONNECTION_DELETE_FAILURE = 'PUBLICIZE_CONNECTION_DELETE_FAILURE';
 export const PUBLICIZE_CONNECTION_RECEIVE = 'PUBLICIZE_CONNECTION_RECEIVE';
diff --git a/client/state/sharing/publicize/actions.js b/client/state/sharing/publicize/actions.js
index a8b87eebb7b3..2b4bb57c5119 100644
--- a/client/state/sharing/publicize/actions.js
+++ b/client/state/sharing/publicize/actions.js
@@ -2,7 +2,6 @@ import { translate } from 'i18n-calypso';
 import wpcom from 'calypso/lib/wp';
 import {
 	PUBLICIZE_CONNECTION_CREATE,
-	PUBLICIZE_CONNECTION_CREATE_FAILURE,
 	PUBLICIZE_CONNECTION_DELETE,
 	PUBLICIZE_CONNECTION_DELETE_FAILURE,
 	PUBLICIZE_CONNECTION_RECEIVE,
@@ -155,7 +154,6 @@ export function createSiteConnection( siteId, keyringConnectionId, externalUserI
 				);
 			} )
 			.catch( ( error ) => {
-				dispatch( failCreateConnection( error ) );
 				dispatch(
 					errorNotice(
 						error.message ||
@@ -257,19 +255,6 @@ export function deleteSiteConnection( connection ) {
 			} );
 }
 
-/**
- * Returns an action object to be used in signalling that creating a Publicize
- * connection has failed.
- * @param  {Object} error Error object
- * @returns {Object}       Action object
- */
-export function failCreateConnection( error ) {
-	return {
-		type: PUBLICIZE_CONNECTION_CREATE_FAILURE,
-		error,
-	};
-}
-
 /**
  * Returns an action object to be used in signalling that a network request for
  * removing a Publicize connection has been received.
diff --git a/client/state/sharing/publicize/test/actions.js b/client/state/sharing/publicize/test/actions.js
index 185ba56abd95..0c0e6d9e77b5 100644
--- a/client/state/sharing/publicize/test/actions.js
+++ b/client/state/sharing/publicize/test/actions.js
@@ -1,6 +1,6 @@
 import {
+	NOTICE_CREATE,
 	PUBLICIZE_CONNECTION_CREATE,
-	PUBLICIZE_CONNECTION_CREATE_FAILURE,
 	PUBLICIZE_CONNECTION_DELETE,
 	PUBLICIZE_CONNECTION_DELETE_FAILURE,
 	PUBLICIZE_CONNECTION_RECEIVE,
@@ -16,7 +16,6 @@ import {
 	createSiteConnection,
 	deleteSiteConnection,
 	deleteConnection,
-	failCreateConnection,
 	fetchConnection,
 	fetchConnections,
 	receiveConnections,
@@ -140,17 +139,20 @@ describe( 'actions', () => {
 			} );
 		} );
 
-		test( 'should dispatch fail action when request fails', () => {
+		test( 'should dispatch notice action when request fails', () => {
 			return createSiteConnection(
 				77203074,
 				2,
 				1
 			)( spy ).then( () => {
 				expect( spy ).toHaveBeenCalledWith( {
-					type: PUBLICIZE_CONNECTION_CREATE_FAILURE,
-					error: expect.objectContaining( {
-						message: 'An active access token must be used to access publicize connections.',
-					} ),
+					type: NOTICE_CREATE,
+					notice: {
+						text: 'An active access token must be used to access publicize connections.',
+						noticeId: 'publicize',
+						showDismiss: true,
+						status: 'is-error',
+					},
 				} );
 			} );
 		} );
@@ -257,19 +259,6 @@ describe( 'actions', () => {
 		} );
 	} );
 
-	describe( 'failCreateConnection()', () => {
-		test( 'should return an action object', () => {
-			const action = failCreateConnection( { message: 'An error occurred' } );
-
-			expect( action ).toEqual( {
-				type: PUBLICIZE_CONNECTION_CREATE_FAILURE,
-				error: {
-					message: 'An error occurred',
-				},
-			} );
-		} );
-	} );
-
 	describe( '#receiveConnections()', () => {
 		test( 'should return an action object', () => {
 			const data = { connections: [ { ID: 2, site_ID: 2916284 } ] };


Reviews:
user: login: aduth
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-12T19:02:29Z
user: login: aduth
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-12T19:04:28Z
user: login: tyxla
body: LGTM 👍 

There's one alternative for the removed Facebook profiles clarification string, feel free to ship with or without going with it.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-14T15:13:57Z
user: login: aduth
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T15:21:02Z
user: login: aduth
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T15:44:31Z
user: login: tyxla
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T16:07:01Z
user: login: aduth
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-14T17:39:07Z
user: login: jsnajdr
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-15T06:39:18Z
user: login: tyxla
body: Thanks 👍 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-15T09:24:27Z

Review comments:
diff_hunk: @@ -450,27 +447,29 @@ export class SharingService extends Component {
 			// At this point, if there are no available accounts to
 			// select, we must assume the user closed the popup
 			// before completing the authorization step.
-			this.props.failCreateConnection( {
-				message: this.props.translate(
+			this.props.warningNotice(
path: client/sites/marketing/connections/service.jsx
user: login: aduth
body: Choosing warning notices for consistency with existing behavior, reserving error notices for unexpected failures.

https://github.com/Automattic/wp-calypso/blob/ee8dcfccfc2a4900a6bebb8004fc00617d620671/client/sites/marketing/connections/service.jsx#L198-L201
created_at: 2025-05-12T19:02:29Z
author_association: MEMBER
diff_hunk: @@ -14,35 +13,15 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
-						'The Facebook connection could not be made because this account does not have access to any Pages.',
-						{
-							context: 'Sharing: Jetpack Social connection error',
-						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
-						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
-							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
-						{
-							components: {
-								a: (
-									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
-										target="_blank"
-										rel="noopener noreferrer"
-									/>
-								),
-							},
-						}
-					),
path: client/sites/marketing/connections/services/facebook.js
user: login: aduth
body: This was added "temporarily" 7 years ago. The referenced URL section no longer exists. 

That being said, I think it's potentially confusing if someone would want to connect their Facebook profile, not realizing it's limited to Pages only. There's [some mention of this in the equivalent current support content](https://wordpress.com/support/post-to-facebook/#:~:text=Note%2C%20Facebook%20Pages%20are%20not%20the%20same%20as%20Facebook%20Profiles.%20You%20can%20only%20automatically%20share%20to%20a%20Facebook%20Page.).
created_at: 2025-05-12T19:04:28Z
author_association: MEMBER
diff_hunk: @@ -450,27 +447,29 @@ export class SharingService extends Component {
 			// At this point, if there are no available accounts to
 			// select, we must assume the user closed the popup
 			// before completing the authorization step.
-			this.props.failCreateConnection( {
-				message: this.props.translate(
+			this.props.warningNotice(
path: client/sites/marketing/connections/service.jsx
user: login: tyxla
body: 👍 

How convenient that the warning notice prop was already there 😉  
created_at: 2025-05-14T15:08:01Z
author_association: MEMBER
diff_hunk: @@ -14,35 +13,15 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
-						'The Facebook connection could not be made because this account does not have access to any Pages.',
-						{
-							context: 'Sharing: Jetpack Social connection error',
-						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
-						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
-							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
-						{
-							components: {
-								a: (
-									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
-										target="_blank"
-										rel="noopener noreferrer"
-									/>
-								),
-							},
-						}
-					),
path: client/sites/marketing/connections/services/facebook.js
user: login: tyxla
body: I wonder if we can keep the string but change the link. Seems like [this one](https://wordpress.com/support/post-to-facebook/) has it:

> Note, [Facebook Pages](https://www.facebook.com/help/104002523024878?helpref=faq_content) are not the same as Facebook Profiles. You can only automatically share to a Facebook Page.
created_at: 2025-05-14T15:10:28Z
author_association: MEMBER
diff_hunk: @@ -45,11 +45,12 @@ export class GoogleMyBusiness extends SharingService {
 		this.props
 			.connectGoogleMyBusinessLocation( this.props.siteId, keyringConnectionId, externalUserId )
 			.catch( () => {
-				this.props.failCreateConnection( {
-					message: this.props.translate( 'Error while linking your site to %(service)s.', {
+				this.props.warningNotice(
+					this.props.translate( 'Error while linking your site to %(service)s.', {
 						args: { service: this.props.service.label },
 					} ),
-				} );
+					{ id: 'publicize' }
path: client/sites/marketing/connections/services/google-my-business.js
user: login: tyxla
body: Not sure we need to keep the same ID for all of those, since the chance to see two different types of warnings on the same page sounds minimal, but I'll leave it to your judgment.
created_at: 2025-05-14T15:11:21Z
author_association: MEMBER
diff_hunk: @@ -45,11 +45,12 @@ export class GoogleMyBusiness extends SharingService {
 		this.props
 			.connectGoogleMyBusinessLocation( this.props.siteId, keyringConnectionId, externalUserId )
 			.catch( () => {
-				this.props.failCreateConnection( {
-					message: this.props.translate( 'Error while linking your site to %(service)s.', {
+				this.props.warningNotice(
+					this.props.translate( 'Error while linking your site to %(service)s.', {
 						args: { service: this.props.service.label },
 					} ),
-				} );
+					{ id: 'publicize' }
path: client/sites/marketing/connections/services/google-my-business.js
user: login: aduth
body: I added the ID largely for consistency with other warning notices we're already showing for the same kind of issue:

https://github.com/Automattic/wp-calypso/blob/ee8dcfccfc2a4900a6bebb8004fc00617d620671/client/sites/marketing/connections/service.jsx#L198-L205
created_at: 2025-05-14T15:21:02Z
author_association: MEMBER
diff_hunk: @@ -14,35 +13,15 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
-						'The Facebook connection could not be made because this account does not have access to any Pages.',
-						{
-							context: 'Sharing: Jetpack Social connection error',
-						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
-						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
-							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
-						{
-							components: {
-								a: (
-									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
-										target="_blank"
-										rel="noopener noreferrer"
-									/>
-								),
-							},
-						}
-					),
path: client/sites/marketing/connections/services/facebook.js
user: login: aduth
body: I'll add it back but keep the "temporary" comment removed. I might also want to double-check support for array children in notices, since the other code uses simple string values.
created_at: 2025-05-14T15:44:31Z
author_association: MEMBER
diff_hunk: @@ -14,35 +13,15 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
-						'The Facebook connection could not be made because this account does not have access to any Pages.',
-						{
-							context: 'Sharing: Jetpack Social connection error',
-						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
-						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
-							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
-						{
-							components: {
-								a: (
-									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
-										target="_blank"
-										rel="noopener noreferrer"
-									/>
-								),
-							},
-						}
-					),
path: client/sites/marketing/connections/services/facebook.js
user: login: tyxla
body: Makes sense to me
created_at: 2025-05-14T16:07:01Z
author_association: MEMBER
diff_hunk: @@ -14,35 +13,15 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
-						'The Facebook connection could not be made because this account does not have access to any Pages.',
-						{
-							context: 'Sharing: Jetpack Social connection error',
-						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
-						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
-							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
-						{
-							components: {
-								a: (
-									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
-										target="_blank"
-										rel="noopener noreferrer"
-									/>
-								),
-							},
-						}
-					),
path: client/sites/marketing/connections/services/facebook.js
user: login: aduth
body: Added back in 212bd98fd91. I also tested to confirm it displays as expected:

![Screenshot 2025-05-14 at 1 35 38 PM](https://github.com/user-attachments/assets/a4ce9d1c-aaca-4f1e-a581-f6e9bcaa7469)

To my earlier point: Notices should already be able to support element children, because `translate` can return React elements as well:

https://github.com/Automattic/wp-calypso/blob/8513c256f35929c3ec880524e7f6820f27b29a45/packages/i18n-calypso/src/i18n.js#L384-L389

Strangely, I would expect this notice would only be shown when successfully connecting to a Facebook account without any associated pages, but I also noticed the alert is shown when cancelling the connection altogether. Fortunately it made testing easier for me, since my personal Facebook account _is_ associated with a Page 😅 
created_at: 2025-05-14T17:39:07Z
author_association: MEMBER
diff_hunk: @@ -14,35 +14,32 @@ export class Facebook extends SharingService {
 
 	didKeyringConnectionSucceed( availableExternalAccounts ) {
 		if ( availableExternalAccounts.length === 0 ) {
-			this.props.failCreateConnection( {
-				message: [
-					this.props.translate(
+			this.props.warningNotice(
+				<>
+					{ this.props.translate(
 						'The Facebook connection could not be made because this account does not have access to any Pages.',
 						{
 							context: 'Sharing: Jetpack Social connection error',
 						}
-					),
-					// Append temporary message to inform of Facebook API change
-					' ',
-					this.props.translate(
+					) }{ ' ' }
+					{ this.props.translate(
 						'Facebook supports Jetpack Social connections to Facebook Pages, but not to Facebook Profiles. ' +
 							'{{a}}Learn More about Jetpack Social for Facebook{{/a}}',
 						{
 							components: {
 								a: (
 									<a
-										href={ localizeUrl(
-											'https://wordpress.com/support/publicize/#facebook-pages'
-										) }
+										href={ localizeUrl( 'https://wordpress.com/support/post-to-facebook/' ) }
path: client/sites/marketing/connections/services/facebook.js
user: login: jsnajdr
body: Thanks for updating the link, the `#facebook-pages` anchor indeed doesn't exist any more.
created_at: 2025-05-15T06:35:52Z
author_association: MEMBER
diff_hunk: @@ -45,11 +45,12 @@ export class GoogleMyBusiness extends SharingService {
 		this.props
 			.connectGoogleMyBusinessLocation( this.props.siteId, keyringConnectionId, externalUserId )
 			.catch( () => {
-				this.props.failCreateConnection( {
-					message: this.props.translate( 'Error while linking your site to %(service)s.', {
+				this.props.warningNotice(
+					this.props.translate( 'Error while linking your site to %(service)s.', {
 						args: { service: this.props.service.label },
 					} ),
-				} );
+					{ id: 'publicize' }
path: client/sites/marketing/connections/services/google-my-business.js
user: login: jsnajdr
body: Yes, the practical effect of the `id` is that you'll never see two notices with the same ID. The newer one will auto-remove the previous one. That sounds good.
created_at: 2025-05-15T06:37:37Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-12T19:02:05Z
body: <details>
<summary>Calypso Live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144303%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303">https://calypso.live?image=registry.a8c.com/calypso/app:build-144303</a>
</td>
</tr>
</table>
</details>
<details>
<summary>Jetpack Cloud live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=jetpack">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144303%26env%3Djetpack%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=jetpack">https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=jetpack</a>
</td>
</tr>
</table>
</details>
<details>
<summary>Automattic for Agencies live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=a8c-for-agencies">(direct link)</a></summary>
<table>
<tr>
<td>
<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=https%3A%2F%2Fcalypso.live%3Fimage%3Dregistry.a8c.com%2Fcalypso%2Fapp%3Abuild-144303%26env%3Da8c-for-agencies%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=a8c-for-agencies">https://calypso.live?image=registry.a8c.com/calypso/app:build-144303&env=a8c-for-agencies</a>
</td>
</tr>
</table>
</details>
<!--calypso-live-watermark:apr@v1-->
author_association: NONE
user: login: matticbot
created_at: 2025-05-12T19:09:01Z
body: **This PR modifies the release build for the following Calypso Apps:**

_For info about this notification, see here: PCYsg-OT6-p2_

* help-center
* notifications
* wpcom-block-editor

To test WordPress.com changes, run `install-plugin.sh $pluginSlug fix/publicize-error-create-connection` on your sandbox.
<!--calypso-app-artifacts-watermark:apr@v1-->
author_association: CONTRIBUTOR
user: login: matticbot
created_at: 2025-05-12T19:09:08Z
body: <!-- icfy-watermark: c52822 -->
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

**App Entrypoints** (~8 bytes removed 📉 [gzipped])
<details>

```
name                   parsed_size           gzip_size
entry-subscriptions          -52 B  (-0.0%)       -8 B  (-0.0%)
entry-stepper                -52 B  (-0.0%)       -8 B  (-0.0%)
entry-reauth-required        -52 B  (-0.0%)       -8 B  (-0.0%)
entry-main                   -52 B  (-0.0%)       -8 B  (-0.0%)
entry-login                  -52 B  (-0.0%)       -8 B  (-0.0%)
```

Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used.
</details>

**Sections** (~89 bytes removed 📉 [gzipped])
<details>

```
name            parsed_size           gzip_size
marketing            -104 B  (-0.0%)      -51 B  (-0.0%)
jetpack-social       -104 B  (-0.0%)      -51 B  (-0.0%)
posts-custom          -58 B  (-0.0%)      -18 B  (-0.0%)
posts                 -58 B  (-0.0%)      -18 B  (-0.0%)
media                 -58 B  (-0.0%)      -18 B  (-0.0%)
home                  -58 B  (-0.0%)      -20 B  (-0.0%)
```

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.
</details>

**Async-loaded Components** (~18 bytes removed 📉 [gzipped])
<details>

```
name                                        parsed_size           gzip_size
async-load-design-blocks                          -58 B  (-0.0%)      -18 B  (-0.0%)
async-load-calypso-post-editor-media-modal        -58 B  (-0.0%)      -18 B  (-0.0%)
```

React components that are loaded lazily, when a certain part of UI is displayed for the first time.
</details>

**Legend**
<details>
<summary>What is parsed and gzip size?</summary>

**Parsed Size:** Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
**Gzip Size:** Compressed size of the JS and CSS files. This much data needs to be downloaded over network.
</details>

Generated by performance advisor bot at [iscalypsofastyet.com](http://iscalypsofastyet.com).
author_association: CONTRIBUTOR