Skip to content

Commit 41f2251

Browse files
CGastrellclaudesimison
authored
Network Admin: Migrate to unified AdminPage header (#47912)
* Network Admin: Add React entry point for unified header Add network-admin.tsx entry point that renders the AdminPage component from @automattic/jetpack-components around the server-rendered network admin page content. Includes Sites/Settings navigation buttons in the header actions slot and proper content spacing via Container. Add the network-admin entry to the Jetpack plugin webpack config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Network Admin: Replace legacy masthead with unified AdminPage header Replace Jetpack_Admin_Page::wrap_ui() on both Network Sites and Network Settings pages with the new React-based AdminPage wrapper. The PHP page content is rendered in a hidden div and relocated into the React tree at mount time, preserving all existing functionality. - Remove old wrapper style hooks (dops-css, genericons) - Add admin_init_network_page() to enqueue the new JS/CSS bundle - Localize Sites/Settings navigation URLs for the header action buttons - Remove network_admin_page_header() calls (old PHP masthead) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use sentence case in page names Co-authored-by: Mikael Korpela <mikael@ihminen.org> * Clean out contents from the page * Replace site-specific links with generic support link in the footer * Remove buttons * changelog * fix types * Update var names and remove manual dependency --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Mikael Korpela <mikael@ihminen.org> Co-authored-by: Mikael Korpela <mikael.korpela@automattic.com>
1 parent 8cc19e8 commit 41f2251

File tree

9 files changed

+185
-19
lines changed

9 files changed

+185
-19
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: changed
3+
4+
Update network admin settings visually.

projects/js-packages/components/components/jetpack-footer/index.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ import JetpackLogo from '../jetpack-logo/index.tsx';
99
import type { JetpackFooterProps, JetpackFooterMenuItem } from './types.ts';
1010
import type { FC } from 'react';
1111

12+
declare global {
13+
interface Window {
14+
JetpackNetworkAdminData?: {
15+
sitesUrl: string;
16+
settingsUrl: string;
17+
};
18+
}
19+
}
20+
1221
/**
1322
* JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right.
1423
*
@@ -18,7 +27,7 @@ import type { FC } from 'react';
1827
const JetpackFooter: FC< JetpackFooterProps > = ( { className, menu, ...otherProps } ) => {
1928
let items: JetpackFooterMenuItem[] = [];
2029

21-
if ( ! isWpcomPlatformSite() ) {
30+
if ( ! isWpcomPlatformSite() && ! window?.JetpackNetworkAdminData ) {
2231
items = [
2332
{
2433
label: __( 'Products', 'jetpack-components' ),

projects/js-packages/components/components/jetpack-footer/test/component.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import JetpackFooter from '../index.tsx';
66
describe( 'JetpackFooter', () => {
77
const className = 'sample-classname';
88

9+
afterEach( () => {
10+
delete window.JetpackNetworkAdminData;
11+
} );
12+
913
describe( 'Render the component', () => {
1014
const menu = [
1115
{
@@ -73,6 +77,18 @@ describe( 'JetpackFooter', () => {
7377
expect( button ).toHaveAttribute( 'tabindex', '0' );
7478
} );
7579

80+
it( 'should hide default links when JetpackNetworkAdminData is present', () => {
81+
window.JetpackNetworkAdminData = {
82+
sitesUrl: '/',
83+
settingsUrl: '/',
84+
};
85+
86+
render( <JetpackFooter /> );
87+
88+
expect( screen.queryByRole( 'link', { name: 'Products' } ) ).not.toBeInTheDocument();
89+
expect( screen.queryByRole( 'link', { name: 'Help' } ) ).not.toBeInTheDocument();
90+
} );
91+
7692
it( 'should match the snapshot', () => {
7793
const { container } = render( <JetpackFooter className={ className } menu={ menu } /> );
7894
expect( container ).toMatchSnapshot( 'all props' );
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import {
2+
AdminPage,
3+
ThemeProvider,
4+
Container,
5+
Col,
6+
getRedirectUrl,
7+
} from '@automattic/jetpack-components';
8+
import { createRoot } from '@wordpress/element';
9+
import { __ } from '@wordpress/i18n';
10+
import { useEffect, useRef } from 'react';
11+
12+
type PageType = 'sites' | 'settings';
13+
14+
declare global {
15+
interface Window {
16+
JetpackNetworkAdminData?: {
17+
sitesUrl: string;
18+
settingsUrl: string;
19+
};
20+
}
21+
}
22+
23+
const PAGE_CONFIG: Record< PageType, { title: string; subTitle: string } > = {
24+
sites: {
25+
title: __( 'Network sites', 'jetpack' ),
26+
subTitle: __( 'Manage Jetpack connections across your network.', 'jetpack' ),
27+
},
28+
settings: {
29+
title: __( 'Network settings', 'jetpack' ),
30+
subTitle: __( 'Configure Jetpack settings for your entire network.', 'jetpack' ),
31+
},
32+
};
33+
34+
/**
35+
* Wraps the server-rendered network admin page content with the unified
36+
* Jetpack AdminPage header and footer.
37+
*
38+
* @param {object} props - Component props.
39+
* @param {PageType} props.pageType - The current page type.
40+
* @return {import('react').ReactNode} The network admin page.
41+
*/
42+
function NetworkAdminApp( { pageType }: { pageType: PageType } ) {
43+
const config = PAGE_CONFIG[ pageType ];
44+
const contentRef = useRef< HTMLDivElement >( null );
45+
46+
useEffect( () => {
47+
const phpContent = document.getElementById( 'jp-network-admin-content' );
48+
if ( contentRef.current && phpContent ) {
49+
phpContent.style.display = '';
50+
contentRef.current.appendChild( phpContent );
51+
}
52+
}, [] );
53+
54+
return (
55+
<AdminPage
56+
title={ config.title }
57+
subTitle={ config.subTitle }
58+
optionalMenuItems={ [
59+
{
60+
label: __( 'Support', 'jetpack' ),
61+
href: getRedirectUrl( 'jetpack-support' ),
62+
},
63+
] }
64+
>
65+
<Container horizontalSpacing={ 5 } horizontalGap={ 0 }>
66+
<Col>
67+
<div ref={ contentRef } />
68+
</Col>
69+
</Container>
70+
</AdminPage>
71+
);
72+
}
73+
74+
const container = document.getElementById( 'jp-network-admin-root' );
75+
if ( container ) {
76+
const pageType = ( container.dataset.page as PageType ) || 'sites';
77+
const root = createRoot( container );
78+
root.render(
79+
<ThemeProvider targetDom={ document.body }>
80+
<NetworkAdminApp pageType={ pageType } />
81+
</ThemeProvider>
82+
);
83+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: enhancement
3+
4+
Update network admin settings visually.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: enhancement
3+
4+
Network Admin: Replace legacy PHP masthead on Network Sites and Network Settings pages with the unified AdminPage header from @automattic/jetpack-components.

projects/plugins/jetpack/class.jetpack-network.php

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -285,15 +285,8 @@ public function add_network_admin_menu() {
285285
add_menu_page( 'Jetpack', 'Jetpack', 'jetpack_network_admin_page', 'jetpack', array( $this, 'wrap_network_admin_page' ), $icon, 3 );
286286
$jetpack_sites_page_hook = add_submenu_page( 'jetpack', __( 'Jetpack Sites', 'jetpack' ), __( 'Sites', 'jetpack' ), 'jetpack_network_sites_page', 'jetpack', array( $this, 'wrap_network_admin_page' ) );
287287
$jetpack_settings_page_hook = add_submenu_page( 'jetpack', __( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'jetpack_network_settings_page', 'jetpack-settings', array( $this, 'wrap_render_network_admin_settings_page' ) );
288-
add_action( "admin_print_styles-$jetpack_sites_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
289-
add_action( "admin_print_styles-$jetpack_settings_page_hook", array( 'Jetpack_Admin_Page', 'load_wrapper_styles' ) );
290-
/**
291-
* As jetpack_register_genericons is by default fired off a hook,
292-
* the hook may have already fired by this point.
293-
* So, let's just trigger it manually.
294-
*/
295-
require_once JETPACK__PLUGIN_DIR . '_inc/genericons.php';
296-
jetpack_register_genericons();
288+
add_action( "load-$jetpack_sites_page_hook", array( $this, 'admin_init_network_page' ) );
289+
add_action( "load-$jetpack_settings_page_hook", array( $this, 'admin_init_network_page' ) );
297290
}
298291

299292
/**
@@ -513,10 +506,64 @@ public function filter_register_request_body( $properties ) {
513506
}
514507

515508
/**
516-
* A hook handler for adding admin pages and subpages.
509+
* Initializes assets for network admin pages.
510+
*
511+
* @since $$next-version$$
512+
*/
513+
public function admin_init_network_page() {
514+
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_network_admin_scripts' ) );
515+
}
516+
517+
/**
518+
* Enqueues the JS and CSS for the unified network admin header.
519+
*
520+
* @since $$next-version$$
521+
*/
522+
public function enqueue_network_admin_scripts() {
523+
$build_dir = JETPACK__PLUGIN_DIR . '_inc/build/';
524+
$script_asset_path = $build_dir . 'network-admin.asset.php';
525+
526+
if ( ! file_exists( $script_asset_path ) ) {
527+
return;
528+
}
529+
530+
$script_asset = require $script_asset_path;
531+
532+
wp_enqueue_script(
533+
'jetpack-network-admin',
534+
plugins_url( '_inc/build/network-admin.js', JETPACK__PLUGIN_FILE ),
535+
$script_asset['dependencies'],
536+
$script_asset['version'],
537+
true
538+
);
539+
540+
wp_enqueue_style(
541+
'jetpack-network-admin',
542+
plugins_url( '_inc/build/network-admin.css', JETPACK__PLUGIN_FILE ),
543+
array(),
544+
$script_asset['version']
545+
);
546+
547+
wp_set_script_translations( 'jetpack-network-admin', 'jetpack' );
548+
549+
wp_localize_script(
550+
'jetpack-network-admin',
551+
'JetpackNetworkAdminData',
552+
array(
553+
'sitesUrl' => network_admin_url( 'admin.php?page=jetpack' ),
554+
'settingsUrl' => network_admin_url( 'admin.php?page=jetpack-settings' ),
555+
)
556+
);
557+
}
558+
559+
/**
560+
* Renders the Network Sites page with the unified admin header.
517561
*/
518562
public function wrap_network_admin_page() {
519-
Jetpack_Admin_Page::wrap_ui( array( $this, 'network_admin_page' ) );
563+
echo '<div id="jp-network-admin-root" data-page="sites"></div>';
564+
echo '<div id="jp-network-admin-content" style="display:none">';
565+
$this->network_admin_page();
566+
echo '</div>';
520567
}
521568

522569
/**
@@ -528,7 +575,6 @@ public function wrap_network_admin_page() {
528575
*/
529576
public function network_admin_page() {
530577
global $current_site;
531-
$this->network_admin_page_header();
532578

533579
$jp = Jetpack::init();
534580

@@ -650,17 +696,19 @@ public function save_network_settings_page() {
650696
}
651697

652698
/**
653-
* A hook handler for adding admin pages and subpages.
699+
* Renders the Network Settings page with the unified admin header.
654700
*/
655701
public function wrap_render_network_admin_settings_page() {
656-
Jetpack_Admin_Page::wrap_ui( array( $this, 'render_network_admin_settings_page' ) );
702+
echo '<div id="jp-network-admin-root" data-page="settings"></div>';
703+
echo '<div id="jp-network-admin-content" style="display:none">';
704+
$this->render_network_admin_settings_page();
705+
echo '</div>';
657706
}
658707

659708
/**
660709
* A hook rendering the admin settings page.
661710
*/
662711
public function render_network_admin_settings_page() {
663-
$this->network_admin_page_header();
664712
$options = wp_parse_args( get_site_option( $this->settings_name ), $this->setting_defaults );
665713

666714
$modules = array();

projects/plugins/jetpack/tools/webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ module.exports = [
157157
},
158158
},
159159
'plugins-page': path.join( __dirname, '../_inc/client', 'plugins-entry.js' ),
160+
'network-admin': path.join( __dirname, '../_inc/client', 'network-admin.tsx' ),
160161
},
161162
plugins: [
162163
...sharedWebpackConfig.plugins,

projects/plugins/jetpack/views/admin/network-settings.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@
2626
<?php endif; ?>
2727

2828
<div class="wrap">
29-
<h2><?php esc_html_e( 'Network Settings', 'jetpack' ); ?></h2>
3029
<form action="edit.php?action=jetpack-network-settings" method="POST">
31-
<h3><?php echo esc_html_x( 'Global', 'Affects all sites in a Multisite network.', 'jetpack' ); ?></h3>
32-
<p><?php esc_html_e( 'These settings affect all sites on the network.', 'jetpack' ); ?></p>
3330
<?php wp_nonce_field( 'jetpack-network-settings' ); ?>
3431
<table class="form-table">
3532
<tr valign="top">

0 commit comments

Comments
 (0)