From a4a5be08920b6a388bb7e5224c27a168c0d0bfaf Mon Sep 17 00:00:00 2001 From: Katie Wilkerson Rethman Date: Tue, 26 May 2026 17:12:35 -0500 Subject: [PATCH 1/2] refactor(emails): move Emails from Settings to Audience Configuration (NPPD-1538) Move the Emails management UI from Newspack > Settings > Emails to Audience > Configuration > Emails as the last tab. REST API paths remain stable at /wizard/newspack-settings/emails via a hardcoded REST_BASE constant for backward compatibility. Co-Authored-By: Claude Opus 4.6 --- includes/class-wizards.php | 9 +++++-- .../audience/class-audience-wizard.php | 14 +++++++++-- .../wizards/newspack/class-emails-section.php | 21 +++++++++++----- .../newspack/class-newspack-settings.php | 23 +++++++----------- .../views/setup}/emails/email-preview.scss | 0 .../views/setup}/emails/email-preview.test.js | 0 .../views/setup}/emails/email-preview.tsx | 0 .../views/setup}/emails/emails.scss | 0 .../views/setup}/emails/emails.test.js | 14 ++++------- .../views/setup}/emails/emails.tsx | 8 +++---- .../views/setup}/emails/index.tsx | 13 +++++----- .../views/setup}/emails/settings.tsx | 4 ++-- src/wizards/audience/views/setup/index.js | 6 +++++ src/wizards/newspack/types/index.d.ts | 24 ------------------- .../newspack/views/settings/sections.tsx | 2 -- src/wizards/types/window.d.ts | 5 ++++ 16 files changed, 70 insertions(+), 73 deletions(-) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/email-preview.scss (100%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/email-preview.test.js (100%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/email-preview.tsx (100%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/emails.scss (100%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/emails.test.js (98%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/emails.tsx (97%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/index.tsx (63%) rename src/wizards/{newspack/views/settings => audience/views/setup}/emails/settings.tsx (94%) diff --git a/includes/class-wizards.php b/includes/class-wizards.php index 873b72558f..142f1c9c67 100644 --- a/includes/class-wizards.php +++ b/includes/class-wizards.php @@ -49,7 +49,6 @@ public static function init_wizards() { [ 'sections' => [ 'custom-events' => 'Newspack\Wizards\Newspack\Custom_Events_Section', - 'emails' => 'Newspack\Wizards\Newspack\Emails_Section', 'social-pixels' => 'Newspack\Wizards\Newspack\Pixels_Section', 'recirculation' => 'Newspack\Wizards\Newspack\Recirculation_Section', 'syndication' => 'Newspack\Wizards\Newspack\Syndication_Section', @@ -64,7 +63,13 @@ public static function init_wizards() { ), 'advertising-display-ads' => new Advertising_Display_Ads(), 'advertising-sponsors' => new Advertising_Sponsors(), - 'audience' => new Audience_Wizard(), + 'audience' => new Audience_Wizard( + [ + 'sections' => [ + 'emails' => 'Newspack\Wizards\Newspack\Emails_Section', + ], + ] + ), 'audience-campaigns' => new Audience_Campaigns(), 'audience-content-gates' => new Audience_Content_Gates(), 'audience-donations' => new Audience_Donations(), diff --git a/includes/wizards/audience/class-audience-wizard.php b/includes/wizards/audience/class-audience-wizard.php index f521c1f344..83f5d79006 100644 --- a/includes/wizards/audience/class-audience-wizard.php +++ b/includes/wizards/audience/class-audience-wizard.php @@ -52,9 +52,11 @@ class Audience_Wizard extends Wizard { /** * Audience Configuration Constructor. + * + * @param array $args Optional. Configuration array (e.g. 'sections'). */ - public function __construct() { - parent::__construct(); + public function __construct( $args = [] ) { + parent::__construct( $args ); add_action( 'rest_api_init', [ $this, 'register_api_endpoints' ] ); // Determine active menu items. @@ -114,6 +116,14 @@ public function enqueue_scripts_and_styles() { 'has_metering' => Content_Gate::is_metering_enabled( Memberships::GATE_CPT ), ]; + $data['emails'] = [ + 'isEmailEnhancementsActive' => class_exists( 'Newspack\WooCommerce_Emails' ) && WooCommerce_Emails::is_active(), + 'dependencies' => [ + 'newspackNewsletters' => is_plugin_active( 'newspack-newsletters/newspack-newsletters.php' ), + ], + 'postType' => Emails::POST_TYPE, + ]; + wp_enqueue_script( 'newspack-wizards' ); wp_localize_script( diff --git a/includes/wizards/newspack/class-emails-section.php b/includes/wizards/newspack/class-emails-section.php index 1654f77772..d198a722c6 100644 --- a/includes/wizards/newspack/class-emails-section.php +++ b/includes/wizards/newspack/class-emails-section.php @@ -26,7 +26,16 @@ class Emails_Section extends Wizard_Section { * * @var string */ - protected $wizard_slug = 'newspack-settings'; + protected $wizard_slug = 'newspack-audience'; + + /** + * REST base path for Emails endpoints. + * + * Hardcoded to 'newspack-settings' for API stability — even though + * Emails moved to the Audience wizard in NPPD-1538, external callers + * and the frontend depend on this path. Do NOT change. + */ + const REST_BASE = 'wizard/newspack-settings/emails'; /** * Register the endpoints needed for the wizard screens. @@ -34,7 +43,7 @@ class Emails_Section extends Wizard_Section { public function register_rest_routes() { register_rest_route( NEWSPACK_API_NAMESPACE, - 'wizard/' . $this->wizard_slug . '/emails', + self::REST_BASE, [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ __CLASS__, 'api_get_email_settings' ], @@ -44,7 +53,7 @@ public function register_rest_routes() { if ( WooCommerce_Emails::is_active() ) { register_rest_route( NEWSPACK_API_NAMESPACE, - 'wizard/' . $this->wizard_slug . '/emails', + self::REST_BASE, [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => [ __CLASS__, 'api_update_email_settings' ], @@ -62,7 +71,7 @@ public function register_rest_routes() { if ( class_exists( 'WooCommerce' ) ) { register_rest_route( NEWSPACK_API_NAMESPACE, - 'wizard/' . $this->wizard_slug . '/emails/(?P[A-Za-z0-9_]+)/toggle', + self::REST_BASE . '/(?P[A-Za-z0-9_]+)/toggle', [ 'methods' => WP_REST_Server::EDITABLE, 'callback' => [ __CLASS__, 'api_toggle_wc_email' ], @@ -88,7 +97,7 @@ public function register_rest_routes() { * Get the unified email registry. * * Returns all known email entries keyed by a stable slug. Each entry - * includes metadata used by the Settings > Emails UI. + * includes metadata used by the Audience > Configuration > Emails UI. * * @return array Registry entries keyed by slug. */ @@ -320,7 +329,7 @@ public static function get_email_registry(): array { * Filters the unified email registry. * * Allows external integration plugins to register additional email - * entries that appear in the Settings > Emails UI. + * entries that appear in the Audience > Configuration > Emails UI. * * @param array $registry Registry entries keyed by slug. */ diff --git a/includes/wizards/newspack/class-newspack-settings.php b/includes/wizards/newspack/class-newspack-settings.php index 4e7b6e1180..2ad699f4fb 100644 --- a/includes/wizards/newspack/class-newspack-settings.php +++ b/includes/wizards/newspack/class-newspack-settings.php @@ -7,14 +7,11 @@ namespace Newspack\Wizards\Newspack; -use Newspack\Emails; use Newspack\OAuth; use Newspack\Wizard; use Newspack\Reader_Activation; -use Newspack\Reader_Revenue_Emails; use Newspack\Everlit_Configuration_Manager; use Newspack\Nextdoor; -use Newspack\WooCommerce_Emails; use Newspack\Complianz; use function Newspack\google_site_kit_available; @@ -80,18 +77,6 @@ public function get_local_data() { 'customEvents' => $this->sections['custom-events']->get_data(), ], ], - 'emails' => [ - 'label' => __( 'Emails', 'newspack-plugin' ), - 'sections' => [ - 'emails' => [ - 'dependencies' => [ - 'newspackNewsletters' => is_plugin_active( 'newspack-newsletters/newspack-newsletters.php' ), - ], - 'postType' => Emails::POST_TYPE, - 'isEmailEnhancementsActive' => WooCommerce_Emails::is_active(), - ], - ], - ], 'social' => [ 'label' => __( 'Social', 'newspack-plugin' ), 'nextdoor' => [ @@ -202,6 +187,14 @@ public function enqueue_scripts_and_styles() { /** * JavaScript */ + // Redirect bookmarks from the old Emails location (NPPD-1538). + wp_add_inline_script( + 'newspack-wizards', + 'if(window.location.hash==="#/emails"){window.location.replace("' . + esc_url( admin_url( 'admin.php?page=newspack-audience#/emails' ) ) . '");}', + 'before' + ); + wp_localize_script( 'newspack-wizards', 'newspackSettings', diff --git a/src/wizards/newspack/views/settings/emails/email-preview.scss b/src/wizards/audience/views/setup/emails/email-preview.scss similarity index 100% rename from src/wizards/newspack/views/settings/emails/email-preview.scss rename to src/wizards/audience/views/setup/emails/email-preview.scss diff --git a/src/wizards/newspack/views/settings/emails/email-preview.test.js b/src/wizards/audience/views/setup/emails/email-preview.test.js similarity index 100% rename from src/wizards/newspack/views/settings/emails/email-preview.test.js rename to src/wizards/audience/views/setup/emails/email-preview.test.js diff --git a/src/wizards/newspack/views/settings/emails/email-preview.tsx b/src/wizards/audience/views/setup/emails/email-preview.tsx similarity index 100% rename from src/wizards/newspack/views/settings/emails/email-preview.tsx rename to src/wizards/audience/views/setup/emails/email-preview.tsx diff --git a/src/wizards/newspack/views/settings/emails/emails.scss b/src/wizards/audience/views/setup/emails/emails.scss similarity index 100% rename from src/wizards/newspack/views/settings/emails/emails.scss rename to src/wizards/audience/views/setup/emails/emails.scss diff --git a/src/wizards/newspack/views/settings/emails/emails.test.js b/src/wizards/audience/views/setup/emails/emails.test.js similarity index 98% rename from src/wizards/newspack/views/settings/emails/emails.test.js rename to src/wizards/audience/views/setup/emails/emails.test.js index 48675be039..7aa225c123 100644 --- a/src/wizards/newspack/views/settings/emails/emails.test.js +++ b/src/wizards/audience/views/setup/emails/emails.test.js @@ -169,17 +169,13 @@ const mockEmails = [ describe( 'Emails', () => { beforeEach( () => { jest.clearAllMocks(); - window.newspackSettings = { + window.newspackAudience = { emails: { - sections: { - emails: { - dependencies: { - newspackNewsletters: true, - }, - postType: 'newspack_rr_email', - isEmailEnhancementsActive: false, - }, + dependencies: { + newspackNewsletters: true, }, + postType: 'newspack_rr_email', + isEmailEnhancementsActive: false, }, }; apiFetch.mockResolvedValue( { diff --git a/src/wizards/newspack/views/settings/emails/emails.tsx b/src/wizards/audience/views/setup/emails/emails.tsx similarity index 97% rename from src/wizards/newspack/views/settings/emails/emails.tsx rename to src/wizards/audience/views/setup/emails/emails.tsx index 70a1566117..c21725de38 100644 --- a/src/wizards/newspack/views/settings/emails/emails.tsx +++ b/src/wizards/audience/views/setup/emails/emails.tsx @@ -1,5 +1,5 @@ /** - * Newspack > Settings > Emails > Emails section + * Newspack > Audience > Configuration > Emails section */ /** @@ -57,11 +57,11 @@ const DEFAULT_VIEW: View = { const PageHeading = () =>

{ __( 'Emails', 'newspack-plugin' ) }

; const Emails = () => { - const emailSections = window.newspackSettings.emails.sections; - const [ pluginsReady, setPluginsReady ] = useState( Boolean( emailSections.emails.dependencies.newspackNewsletters ) ); + const emailsConfig = window.newspackAudience.emails; + const [ pluginsReady, setPluginsReady ] = useState( Boolean( emailsConfig.dependencies.newspackNewsletters ) ); const [ data, setData ] = useState< EmailItem[] >( [] ); - const [ postType, setPostType ] = useState< string >( emailSections.emails.postType ); + const [ postType, setPostType ] = useState< string >( emailsConfig.postType ); const [ isLoading, setIsLoading ] = useState( true ); const [ view, setView ] = useState< View >( DEFAULT_VIEW ); const [ error, setError ] = useState< string | null >( null ); diff --git a/src/wizards/newspack/views/settings/emails/index.tsx b/src/wizards/audience/views/setup/emails/index.tsx similarity index 63% rename from src/wizards/newspack/views/settings/emails/index.tsx rename to src/wizards/audience/views/setup/emails/index.tsx index 6f6d6cdaec..975669f6a4 100644 --- a/src/wizards/newspack/views/settings/emails/index.tsx +++ b/src/wizards/audience/views/setup/emails/index.tsx @@ -1,30 +1,29 @@ /** - * Newspack > Settings > Emails + * Newspack > Audience > Configuration > Emails */ /** * Internal dependencies. */ +import { withWizardScreen } from '../../../../../../packages/components/src'; import WizardsTab from '../../../../wizards-tab'; import { default as EmailsSection } from './emails'; import { default as SettingsSection } from './settings'; import WizardSection from '../../../../wizards-section'; -const { emails } = window.newspackSettings; +const { emails } = window.newspackAudience; -function Emails() { +export default withWizardScreen( function Emails() { return ( - { emails?.sections?.emails?.isEmailEnhancementsActive && ( + { emails?.isEmailEnhancementsActive && ( ) } ); -} - -export default Emails; +} ); diff --git a/src/wizards/newspack/views/settings/emails/settings.tsx b/src/wizards/audience/views/setup/emails/settings.tsx similarity index 94% rename from src/wizards/newspack/views/settings/emails/settings.tsx rename to src/wizards/audience/views/setup/emails/settings.tsx index 600050b888..b43084536a 100644 --- a/src/wizards/newspack/views/settings/emails/settings.tsx +++ b/src/wizards/audience/views/setup/emails/settings.tsx @@ -1,5 +1,5 @@ /** - * Newspack > Settings > Emails > Emails section + * Newspack > Audience > Configuration > Emails settings */ /** @@ -38,7 +38,7 @@ const Settings = () => { }; const title = __( "Use WooCommerce's block email editor (alpha)", 'newspack-plugin' ); - const description = __( 'Enable the block-based email editor for transacitonal emails', 'newspack-plugin' ); + const description = __( 'Enable the block-based email editor for transactional emails', 'newspack-plugin' ); return ( diff --git a/src/wizards/audience/views/setup/index.js b/src/wizards/audience/views/setup/index.js index ffd870e78e..5e97a04e06 100644 --- a/src/wizards/audience/views/setup/index.js +++ b/src/wizards/audience/views/setup/index.js @@ -20,6 +20,7 @@ import { withWizard } from '../../../../../packages/components/src'; import Router from '../../../../../packages/components/src/proxied-imports/router'; import ContentGating from './content-gating'; import Payment from './payment'; +import Emails from './emails'; const { HashRouter, Redirect, Route, Switch } = Router; @@ -110,6 +111,10 @@ function AudienceWizard( { confirmAction, pluginRequirements, wizardApiFetch }, label: __( 'Checkout & Payment', 'newspack-plugin' ), path: '/payment', }, + { + label: __( 'Emails', 'newspack-plugin' ), + path: '/emails', + }, ]; tabs = tabs.filter( tab => tab ); @@ -160,6 +165,7 @@ function AudienceWizard( { confirmAction, pluginRequirements, wizardApiFetch }, } /> } /> } /> + } /> diff --git a/src/wizards/newspack/types/index.d.ts b/src/wizards/newspack/types/index.d.ts index e4f25b28b6..70d9ceb173 100644 --- a/src/wizards/newspack/types/index.d.ts +++ b/src/wizards/newspack/types/index.d.ts @@ -70,30 +70,6 @@ declare global { syndication: WizardTab; 'theme-and-brand': WizardTab; seo: WizardTab; - emails: WizardTab & { - sections: { - emails: { - all: { - [ str: string ]: { - label: string; - description: string; - post_id: number; - edit_link: string; - subject: string; - from_name: string; - from_email: string; - reply_to_email: string; - status: string; - type: string; - category: string; - }; - }; - dependencies: Record< string, boolean >; - postType: string; - isEmailEnhancementsActive: boolean; - }; - }; - }; print: WizardTab; 'additional-brands': WizardTab & { sections: { diff --git a/src/wizards/newspack/views/settings/sections.tsx b/src/wizards/newspack/views/settings/sections.tsx index cc8b49c1b2..b1e78a858c 100644 --- a/src/wizards/newspack/views/settings/sections.tsx +++ b/src/wizards/newspack/views/settings/sections.tsx @@ -10,7 +10,6 @@ const settingsTabs = window.newspackSettings; import Seo from './seo'; import Social from './social'; -import Emails from './emails'; import Connections from './connections'; import Syndication from './syndication'; import AdvancedSettings from './advanced-settings'; @@ -24,7 +23,6 @@ type SectionKeys = keyof typeof settingsTabs; const sectionComponents: Partial< Record< SectionKeys | 'default', ( props: { isPartOfSetup?: boolean } ) => React.ReactNode > > = { connections: Connections, social: Social, - emails: Emails, syndication: Syndication, seo: Seo, 'theme-and-brand': ThemeAndBrand, diff --git a/src/wizards/types/window.d.ts b/src/wizards/types/window.d.ts index db80805c35..7ea126217f 100644 --- a/src/wizards/types/window.d.ts +++ b/src/wizards/types/window.d.ts @@ -18,6 +18,11 @@ declare global { }; preview_post: string; preview_archive: string; + emails: { + isEmailEnhancementsActive: boolean; + dependencies: Record< string, boolean >; + postType: string; + }; }; newspackAudienceCampaigns: { api: string; From 8b019846cdd3cb3fb84fca69b3625ad7b45ba9cf Mon Sep 17 00:00:00 2001 From: Katie Wilkerson Rethman Date: Tue, 26 May 2026 17:20:18 -0500 Subject: [PATCH 2/2] fix(emails): use esc_js() for redirect URL in inline script (NPPD-1538) Co-Authored-By: Claude Opus 4.6 --- includes/wizards/newspack/class-newspack-settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/wizards/newspack/class-newspack-settings.php b/includes/wizards/newspack/class-newspack-settings.php index 2ad699f4fb..cfe092e1f9 100644 --- a/includes/wizards/newspack/class-newspack-settings.php +++ b/includes/wizards/newspack/class-newspack-settings.php @@ -191,7 +191,7 @@ public function enqueue_scripts_and_styles() { wp_add_inline_script( 'newspack-wizards', 'if(window.location.hash==="#/emails"){window.location.replace("' . - esc_url( admin_url( 'admin.php?page=newspack-audience#/emails' ) ) . '");}', + esc_js( admin_url( 'admin.php?page=newspack-audience#/emails' ) ) . '");}', 'before' );