Repository: Automattic/wp-calypso
Pull request #103141: STATS-7: Update page tab names + Use TabPanel from Core
Author: login: kangzj
Labels: name: [Feature] Stats
description: Everything related to our analytics product at /stats/
name: Stats
Created: 2025-05-06T01:52:50Z | Merged: 2025-05-07T01:34:17Z

<!--
Link a related 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 and instead attach the [Status] Fix Inbound label to
the linked issue.
-->

Fixes STATS-7

## Proposed Changes

* Moved `StatsDetailsNavigation` out of the highlights component, as it doesn't belong there. And also, moving it out will let it leverage the default margins etc.
* Replaced Calypso tabs with `TabPanel` from Core.
* Fixed [an issue](https://github.com/Automattic/wp-calypso/pull/103141/files#r2074628699) where the Tabs on the Post details page is always hidden.
* Replace tab name of 'Highlights' to 'Post traffic'

## 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.
-->

* More information in STATS-7 and its parent project.

## 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.
-->

* Open `http://calypso.localhost:3000/stats/day/{your-website}` for a website with Subscription module activated
* Scroll to posts & pages
* Click on a post / page
*  Ensure you see the tabs
* Ensure Highlights tab is now 'Post traffic'
* Click the tabs
* Ensure you are taken to Email stats pages
* Ensure nothing looks off

<img width="1084" alt="image" src="https://github.com/user-attachments/assets/66f20587-b574-47f7-9cca-605634209c6d" />


## 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/my-sites/stats/post-detail-highlights-section/index.tsx b/client/my-sites/stats/post-detail-highlights-section/index.tsx
index e530ee0eea30..b8c16e741a95 100644
--- a/client/my-sites/stats/post-detail-highlights-section/index.tsx
+++ b/client/my-sites/stats/post-detail-highlights-section/index.tsx
@@ -1,15 +1,10 @@
 import { Card, Count } from '@automattic/components';
 import { useTranslate } from 'i18n-calypso';
-import QueryJetpackModules from 'calypso/components/data/query-jetpack-modules';
 import QuerySiteStats from 'calypso/components/data/query-site-stats';
 import PostStatsCard from 'calypso/components/post-stats-card';
 import { useSelector } from 'calypso/state';
 import { getCurrentUserLocale } from 'calypso/state/current-user/selectors';
-import isJetpackModuleActive from 'calypso/state/selectors/is-jetpack-module-active';
-import { isSimpleSite } from 'calypso/state/sites/selectors';
-import getEnvStatsFeatureSupportChecks from 'calypso/state/sites/selectors/get-env-stats-feature-supports';
 import { getPostStat } from 'calypso/state/stats/posts/selectors';
-import StatsDetailsNavigation from '../stats-details-navigation';
 import PostLikes from '../stats-post-likes';
 import { truncateWithLimit, getProcessedText } from '../text-utils';
 
@@ -53,67 +48,37 @@ export default function PostDetailHighlightsSection( {
 		title: truncateWithLimit( getProcessedText( post?.title ), POST_STATS_CARD_TITLE_LIMIT ),
 	};
 
-	const { supportsEmailStats } = useSelector( ( state ) =>
-		getEnvStatsFeatureSupportChecks( state, siteId )
-	);
-
-	const isSimple = useSelector( isSimpleSite );
-
-	const isSubscriptionsModuleActive =
-		useSelector( ( state ) => isJetpackModuleActive( state, siteId, 'subscriptions' ) ) ?? false;
-
-	const subscriptionsEnabled = isSimple || isSubscriptionsModuleActive;
-
-	// postId > 0: Show the tabs for posts except for the Home Page (postId = 0).
-	const isEmailTabsAvailable =
-		subscriptionsEnabled &&
-		postId > 0 &&
-		! post?.dont_email_post_to_subs &&
-		post?.date &&
-		// The Newsletter Stats data was never backfilled (internal ref pdDOJh-1Uy-p2).
-		new Date( post?.date ) >= new Date( '2023-05-30' ) &&
-		supportsEmailStats;
-
 	return (
-		<>
-			{ siteId && <QueryJetpackModules siteId={ siteId } /> }
-			{ isEmailTabsAvailable && (
-				<div className="stats-navigation stats-navigation--modernized">
-					<StatsDetailsNavigation postId={ postId } givenSiteId={ siteId } />
-				</div>
+		<div className="stats__post-detail-highlights-section">
+			{ siteId && (
+				<>
+					<QuerySiteStats siteId={ siteId } statType="stats" query={ {} } />
+					<QuerySiteStats siteId={ siteId } statType="statsInsights" />
+				</>
 			) }
-			<div className="stats__post-detail-highlights-section">
-				{ siteId && (
-					<>
-						<QuerySiteStats siteId={ siteId } statType="stats" query={ {} } />
-						<QuerySiteStats siteId={ siteId } statType="statsInsights" />
-					</>
-				) }
-
-				<div className="highlight-cards">
-					<h1 className="highlight-cards-heading">{ translate( 'Highlights' ) }</h1>
-
-					<div className="highlight-cards-list">
-						<PostStatsCard
-							heading={ translate( 'All-time stats' ) }
-							likeCount={ post?.like_count || 0 }
-							post={ postData }
-							viewCount={ viewCount }
-							commentCount={ post?.comment_count || 0 }
-							locale={ userLocale }
-							titleLink={ post?.url || undefined }
-						/>
 
-						<Card className="highlight-card">
-							<div className="highlight-card-heading">
-								<span>{ translate( 'Post likes' ) }</span>
-								<Count count={ post?.like_count || 0 } />
-							</div>
-							<PostLikes siteId={ siteId } postId={ postId } postType={ post?.type } />
-						</Card>
-					</div>
+			<div className="highlight-cards">
+				<h1 className="highlight-cards-heading">{ translate( 'Highlights' ) }</h1>
+				<div className="highlight-cards-list">
+					<PostStatsCard
+						heading={ translate( 'All-time stats' ) }
+						likeCount={ post?.like_count || 0 }
+						post={ postData }
+						viewCount={ viewCount }
+						commentCount={ post?.comment_count || 0 }
+						locale={ userLocale }
+						titleLink={ post?.url || undefined }
+					/>
+
+					<Card className="highlight-card">
+						<div className="highlight-card-heading">
+							<span>{ translate( 'Post likes' ) }</span>
+							<Count count={ post?.like_count || 0 } />
+						</div>
+						<PostLikes siteId={ siteId } postId={ postId } postType={ post?.type } />
+					</Card>
 				</div>
 			</div>
-		</>
+		</div>
 	);
 }
diff --git a/client/my-sites/stats/stats-details-navigation/index.tsx b/client/my-sites/stats/stats-details-navigation/index.tsx
index 90a7f5e2e34f..4d03486bc6d4 100644
--- a/client/my-sites/stats/stats-details-navigation/index.tsx
+++ b/client/my-sites/stats/stats-details-navigation/index.tsx
@@ -1,3 +1,6 @@
+import config from '@automattic/calypso-config';
+import page from '@automattic/calypso-router';
+import { TabPanel } from '@wordpress/components';
 import { useTranslate } from 'i18n-calypso';
 import PropTypes from 'prop-types';
 import { useCallback, useMemo } from 'react';
@@ -5,18 +8,74 @@ import SectionNav from 'calypso/components/section-nav';
 import NavItem from 'calypso/components/section-nav/item';
 import NavTabs from 'calypso/components/section-nav/tabs';
 
-interface propTypes {
+interface StatsDetailsNavigationProps {
 	postId: number;
 	period?: string;
 	statType?: string;
 	givenSiteId: string | number;
 }
 
-function StatsDetailsNavigation( { postId, period, statType, givenSiteId }: propTypes ) {
+function StatsDetailsNavigationImproved( {
+	postId,
+	period,
+	statType,
+	givenSiteId,
+}: StatsDetailsNavigationProps ) {
 	const translate = useTranslate();
 	const tabs = useMemo(
 		() => ( {
-			highlights: translate( 'Highlights' ),
+			highlights: translate( 'Post traffic' ),
+			opens: translate( 'Email opens' ),
+			clicks: translate( 'Email clicks' ),
+		} ),
+		[ translate ]
+	) as { [ key: string ]: string };
+
+	const selectedTab = statType ? statType : 'highlights';
+
+	const tabPanelTabs = useMemo(
+		() =>
+			Object.keys( tabs ).map( ( item ) => {
+				const pathParam = [ 'opens', 'clicks' ].includes( item )
+					? `email/${ item }/${ period || 'day' }`
+					: 'post';
+				return {
+					name: item,
+					title: tabs[ item as keyof typeof tabs ],
+					className: `stats-navigation__${ item }`,
+					path: `/stats/${ pathParam }/${ postId }/${ givenSiteId }`,
+				};
+			} ),
+		[ tabs, postId, period, givenSiteId ]
+	);
+
+	return (
+		<TabPanel
+			className="stats-navigation__tabs"
+			tabs={ tabPanelTabs }
+			initialTabName={ selectedTab }
+			onSelect={ ( tabName ) => {
+				const tab = tabPanelTabs.find( ( tab ) => tab.name === tabName );
+				if ( tab?.path ) {
+					page( tab.path );
+				}
+			} }
+		>
+			{ () => null /* Placeholder div since content is rendered elsewhere */ }
+		</TabPanel>
+	);
+}
+
+function StatsDetailsNavigationLegacy( {
+	postId,
+	period,
+	statType,
+	givenSiteId,
+}: StatsDetailsNavigationProps ) {
+	const translate = useTranslate();
+	const tabs = useMemo(
+		() => ( {
+			highlights: translate( 'Post traffic' ),
 			opens: translate( 'Email opens' ),
 			clicks: translate( 'Email clicks' ),
 		} ),
@@ -56,6 +115,13 @@ function StatsDetailsNavigation( { postId, period, statType, givenSiteId }: prop
 	);
 }
 
+function StatsDetailsNavigation( props: StatsDetailsNavigationProps ) {
+	if ( config.isEnabled( 'stats/navigation-improvement' ) ) {
+		return <StatsDetailsNavigationImproved { ...props } />;
+	}
+	return <StatsDetailsNavigationLegacy { ...props } />;
+}
+
 StatsDetailsNavigation.propTypes = {
 	postId: PropTypes.number.isRequired,
 	period: PropTypes.string,
diff --git a/client/my-sites/stats/stats-post-detail/index.jsx b/client/my-sites/stats/stats-post-detail/index.jsx
index dfab0043e67a..c7821f5b1f48 100644
--- a/client/my-sites/stats/stats-post-detail/index.jsx
+++ b/client/my-sites/stats/stats-post-detail/index.jsx
@@ -10,6 +10,7 @@ import { Component } from 'react';
 import { connect } from 'react-redux';
 import titlecase from 'to-title-case';
 import IllustrationStats from 'calypso/assets/images/stats/illustration-stats.svg';
+import QueryJetpackModules from 'calypso/components/data/query-jetpack-modules';
 import QueryPostStats from 'calypso/components/data/query-post-stats';
 import QueryPosts from 'calypso/components/data/query-posts';
 import EmptyContent from 'calypso/components/empty-content';
@@ -19,9 +20,16 @@ import WebPreview from 'calypso/components/web-preview';
 import { decodeEntities, stripHTML } from 'calypso/lib/formatting';
 import PageHeader from 'calypso/my-sites/stats/components/headers/page-header';
 import Main from 'calypso/my-sites/stats/components/stats-main';
+import StatsDetailsNavigation from 'calypso/my-sites/stats/stats-details-navigation';
 import { getSitePost, getPostPreviewUrl } from 'calypso/state/posts/selectors';
 import { countPostLikes } from 'calypso/state/posts/selectors/count-post-likes';
-import { getSiteSlug, isJetpackSite, isSitePreviewable } from 'calypso/state/sites/selectors';
+import isJetpackModuleActive from 'calypso/state/selectors/is-jetpack-module-active';
+import {
+	getSiteSlug,
+	isJetpackSite,
+	isSitePreviewable,
+	isSimpleSite,
+} from 'calypso/state/sites/selectors';
 import getEnvStatsFeatureSupportChecks from 'calypso/state/sites/selectors/get-env-stats-feature-supports';
 import { getPostStat, isRequestingPostStats } from 'calypso/state/stats/posts/selectors';
 import { getSelectedSiteId } from 'calypso/state/ui/selectors';
@@ -116,7 +124,9 @@ class StatsPostDetail extends Component {
 	}
 
 	hasDontSendEmailPostToSubs( metadata ) {
-		return metadata?.some( ( { key } ) => key === '_jetpack_dont_email_post_to_subs' );
+		return metadata?.some(
+			( { key, value } ) => key === '_jetpack_dont_email_post_to_subs' && !! value
+		);
 	}
 
 	getPost() {
@@ -167,6 +177,9 @@ class StatsPostDetail extends Component {
 			showViewLink,
 			previewUrl,
 			supportsUTMStats,
+			isSubscriptionsModuleActive,
+			supportsEmailStats,
+			isSimple,
 		} = this.props;
 
 		const isLoading = isRequestingStats && ! countViews;
@@ -205,6 +218,17 @@ class StatsPostDetail extends Component {
 			titleLogo: null,
 		};
 
+		const subscriptionsEnabled = isSimple || isSubscriptionsModuleActive;
+		// postId > 0: Show the tabs for posts except for the Home Page (postId = 0).
+		const isEmailTabsAvailable =
+			subscriptionsEnabled &&
+			postId > 0 &&
+			! passedPost?.dont_email_post_to_subs &&
+			passedPost?.date &&
+			// The Newsletter Stats data was never backfilled (internal ref pdDOJh-1Uy-p2).
+			new Date( passedPost?.date ) >= new Date( '2023-05-30' ) &&
+			supportsEmailStats;
+
 		return (
 			<Main fullWidthLayout>
 				<PageViewTracker
@@ -213,6 +237,7 @@ class StatsPostDetail extends Component {
 				/>
 				{ siteId && ! isPostHomepage && <QueryPosts siteId={ siteId } postId={ postId } /> }
 				{ siteId && <QueryPostStats siteId={ siteId } postId={ postId } /> }
+				{ siteId && <QueryJetpackModules siteId={ siteId } /> }
 
 				<div className={ postDetailPageClasses }>
 					{ config.isEnabled( 'stats/navigation-improvement' ) ? (
@@ -237,6 +262,16 @@ class StatsPostDetail extends Component {
 						</NavigationHeader>
 					) }
 
+					{ isEmailTabsAvailable && (
+						<div
+							className={ clsx( 'stats-navigation', 'stats-navigation--modernized', {
+								'stats-navigation--improved': config.isEnabled( 'stats/navigation-improvement' ),
+							} ) }
+						>
+							<StatsDetailsNavigation postId={ postId } givenSiteId={ siteId } />
+						</div>
+					) }
+
 					<PostDetailHighlightsSection siteId={ siteId } postId={ postId } post={ passedPost } />
 
 					<StatsPlaceholder isLoading={ isLoading } />
@@ -290,7 +325,8 @@ const connectComponent = connect( ( state, { postId } ) => {
 	const isPreviewable = isSitePreviewable( state, siteId );
 	const isPostHomepage = postId === 0;
 	const countLikes = countPostLikes( state, siteId, postId ) || 0;
-	const { supportsUTMStats } = getEnvStatsFeatureSupportChecks( state, siteId );
+	const { supportsUTMStats, supportsEmailStats } = getEnvStatsFeatureSupportChecks( state, siteId );
+	const isSimple = isSimpleSite( state, siteId );
 
 	return {
 		post: getSitePost( state, siteId, postId ),
@@ -305,6 +341,9 @@ const connectComponent = connect( ( state, { postId } ) => {
 		previewUrl: getPostPreviewUrl( state, siteId, postId ),
 		siteId,
 		supportsUTMStats,
+		isSubscriptionsModuleActive: isJetpackModuleActive( state, siteId, 'subscriptions', true ),
+		supportsEmailStats,
+		isSimple,
 	};
 } );
 


Reviews:
user: login: kangzj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T01:54:02Z
user: login: kangzj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T02:17:36Z
user: login: kangzj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T05:42:12Z
user: login: kangzj
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T05:43:50Z
user: login: Nikschavan
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-06T06:43:53Z
user: login: simison
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-08T07:25:23Z

Review comments:
diff_hunk: @@ -53,67 +48,37 @@ export default function PostDetailHighlightsSection( {
 		title: truncateWithLimit( getProcessedText( post?.title ), POST_STATS_CARD_TITLE_LIMIT ),
 	};
 
-	const { supportsEmailStats } = useSelector( ( state ) =>
-		getEnvStatsFeatureSupportChecks( state, siteId )
-	);
-
-	const isSimple = useSelector( isSimpleSite );
-
-	const isSubscriptionsModuleActive =
-		useSelector( ( state ) => isJetpackModuleActive( state, siteId, 'subscriptions' ) ) ?? false;
-
-	const subscriptionsEnabled = isSimple || isSubscriptionsModuleActive;
-
-	// postId > 0: Show the tabs for posts except for the Home Page (postId = 0).
-	const isEmailTabsAvailable =
-		subscriptionsEnabled &&
-		postId > 0 &&
-		! post?.dont_email_post_to_subs &&
-		post?.date &&
-		// The Newsletter Stats data was never backfilled (internal ref pdDOJh-1Uy-p2).
-		new Date( post?.date ) >= new Date( '2023-05-30' ) &&
-		supportsEmailStats;
-
 	return (
-		<>
-			{ siteId && <QueryJetpackModules siteId={ siteId } /> }
-			{ isEmailTabsAvailable && (
path: client/my-sites/stats/post-detail-highlights-section/index.tsx
user: login: kangzj
body: Navigation doesn't belong to highlights, so moved to post details.
created_at: 2025-05-06T01:54:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -116,7 +124,9 @@ class StatsPostDetail extends Component {
 	}
 
 	hasDontSendEmailPostToSubs( metadata ) {
-		return metadata?.some( ( { key } ) => key === '_jetpack_dont_email_post_to_subs' );
+		return metadata?.some(
+			( { key, value } ) => key === '_jetpack_dont_email_post_to_subs' && !! value
path: client/my-sites/stats/stats-post-detail/index.jsx
user: login: kangzj
body: @simison I think we should check the value here as well, because I've seen heaps of post which definitely have emails out already, but the meta exists with value of an empty string ''.
created_at: 2025-05-06T02:17:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,22 +1,81 @@
+import config from '@automattic/calypso-config';
+import page from '@automattic/calypso-router';
+import { TabPanel } from '@wordpress/components';
 import { useTranslate } from 'i18n-calypso';
 import PropTypes from 'prop-types';
 import { useCallback, useMemo } from 'react';
 import SectionNav from 'calypso/components/section-nav';
 import NavItem from 'calypso/components/section-nav/item';
 import NavTabs from 'calypso/components/section-nav/tabs';
 
-interface propTypes {
+interface StatsDetailsNavigationProps {
 	postId: number;
 	period?: string;
 	statType?: string;
 	givenSiteId: string | number;
 }
 
-function StatsDetailsNavigation( { postId, period, statType, givenSiteId }: propTypes ) {
+function StatsDetailsNavigationImproved( {
+	postId,
+	period,
+	statType,
+	givenSiteId,
+}: StatsDetailsNavigationProps ) {
 	const translate = useTranslate();
 	const tabs = useMemo(
 		() => ( {
-			highlights: translate( 'Highlights' ),
+			highlights: translate( 'Post traffic' ),
path: client/my-sites/stats/stats-details-navigation/index.tsx
user: login: kangzj
body: Renaming the tab!
created_at: 2025-05-06T05:42:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -205,6 +218,17 @@ class StatsPostDetail extends Component {
 			titleLogo: null,
 		};
 
+		const subscriptionsEnabled = isSimple || isSubscriptionsModuleActive;
path: client/my-sites/stats/stats-post-detail/index.jsx
user: login: kangzj
body: Code here is mostly moved from https://github.com/Automattic/wp-calypso/pull/103141/files#diff-fc93fdb828c96efc52107151a3c2dff45c20e0702e831cabeed908735a856632L56
created_at: 2025-05-06T05:43:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -116,7 +124,9 @@ class StatsPostDetail extends Component {
 	}
 
 	hasDontSendEmailPostToSubs( metadata ) {
-		return metadata?.some( ( { key } ) => key === '_jetpack_dont_email_post_to_subs' );
+		return metadata?.some(
+			( { key, value } ) => key === '_jetpack_dont_email_post_to_subs' && !! value
path: client/my-sites/stats/stats-post-detail/index.jsx
user: login: simison
body: @kangzj you can check with Loop team on changes on Newsletters/subscriptions UX if needed. Thanks! :-)
created_at: 2025-05-08T07:25:23Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-06T01:53:03Z
body: <details>
<summary>Calypso Live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-142884">(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-142884%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-142884">https://calypso.live?image=registry.a8c.com/calypso/app:build-142884</a>
</td>
</tr>
</table>
</details>
<details>
<summary>Jetpack Cloud live <a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-142884&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-142884%26env%3Djetpack%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-142884&env=jetpack">https://calypso.live?image=registry.a8c.com/calypso/app:build-142884&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-142884&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-142884%26env%3Da8c-for-agencies%26flags%3Doauth&choe=UTF-8" />
</td>
<td>
<a href="https://calypso.live?image=registry.a8c.com/calypso/app:build-142884&env=a8c-for-agencies">https://calypso.live?image=registry.a8c.com/calypso/app:build-142884&env=a8c-for-agencies</a>
</td>
</tr>
</table>
</details>
<!--calypso-live-watermark:apr@v1-->
author_association: NONE
user: login: matticbot
created_at: 2025-05-06T01:56:35Z
body: **This PR modifies the release build for the following Calypso Apps:**

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

* notifications
* odyssey-stats

To test WordPress.com changes, run `install-plugin.sh $pluginSlug update/page-tab-names` on your sandbox.
<!--calypso-app-artifacts-watermark:apr@v1-->
author_association: CONTRIBUTOR
user: login: matticbot
created_at: 2025-05-06T01:58:53Z
body: <!-- icfy-watermark: c52822 -->
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

**Sections** (~209 bytes added 📈 [gzipped])
<details>

```
name   parsed_size           gzip_size
stats       +850 B  (+0.1%)     +209 B  (+0.1%)
```

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** (~29 bytes added 📈 [gzipped])
<details>

```
name                                                 parsed_size           gzip_size
async-load-calypso-my-sites-stats-stats-post-detail       +151 B  (+0.4%)      +29 B  (+0.3%)
```

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
user: login: kangzj
created_at: 2025-05-06T05:39:17Z
body: I understand the PR could be split into multiple one, but we are kinda nearing the deadline, so bear with me if this one is slightly larger than others. Thanks all! 😄 
author_association: CONTRIBUTOR
user: login: a8ci18n
created_at: 2025-05-07T03:20:59Z
body: This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/17452978

Some locales (Hebrew, Japanese) have been temporarily machine-translated due to translator availability. All other translations are usually ready within a few days. Untranslated and machine-translated strings will be sent for translation next Monday and are expected to be completed by the following Friday.

Thank you @kangzj for including a screenshot in the description! This is really helpful for our translators.
author_association: NONE