Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1d6f0cc
Add empty private-viewers.php feature
mmtr Nov 19, 2025
1b806f4
Add menu that displays an empty page
mmtr Nov 19, 2025
d5354dd
Add basic React component
mmtr Nov 19, 2025
23dfec1
Render dataview and fetch viewers from API
mmtr Nov 19, 2025
16d49e6
Implement pagination
mmtr Nov 19, 2025
98ac558
Add changelog
mmtr Nov 19, 2025
01e00b6
Disable search and sorting
mmtr Nov 19, 2025
4acffa7
Polish layout
mmtr Nov 19, 2025
97d2470
Better loading status
mmtr Nov 19, 2025
f6738ec
Bail on non-private sites
mmtr Nov 19, 2025
8f2a42f
Better empty layout
mmtr Nov 20, 2025
463698f
Render avatar
mmtr Nov 20, 2025
7ea865a
Move pagination to frontend and fetch all viewers
mmtr Nov 20, 2025
317be86
Add filtering and sorting
mmtr Nov 20, 2025
840bb0a
Add status column
mmtr Nov 20, 2025
26b4ca5
Fetch all viewers (incl. pending viewers)
mmtr Nov 20, 2025
7618625
Add more columns
mmtr Nov 20, 2025
204f35f
Add removal logic
mmtr Nov 21, 2025
3689d22
Add resend logic
mmtr Nov 21, 2025
2326064
move global ts to main file
mmtr Nov 21, 2025
e15091f
Support Atomic sites
mmtr Nov 21, 2025
7967e23
Include basic "Add viewer" button
mmtr Nov 21, 2025
3d06258
Display notices
mmtr Nov 21, 2025
f1d7938
Add text domain to dataviews translations
mmtr Nov 21, 2025
e300389
Reset pnpm-lock.yaml
mmtr Nov 21, 2025
dd15264
Merge branch 'trunk' into dotsite-14-viewers-not-displayed-in-classic…
mmtr Nov 21, 2025
7b1eca5
Update pnpm-lock.yaml
mmtr Nov 21, 2025
5c93f52
add missing dep
mmtr Nov 21, 2025
4799524
regenerate pnpm-lock
mmtr Nov 21, 2025
32a463c
Try avoiding bad minification
mmtr Nov 21, 2025
6f47b9e
Fix i18n errors during build
mmtr Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Render dataview and fetch viewers from API
  • Loading branch information
mmtr committed Nov 19, 2025
commit 23dfec1dc45bb9c573b24763d81340bf1d8c48c9
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions projects/packages/jetpack-mu-wpcom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@wordpress/compose": "7.35.0",
"@wordpress/data": "10.35.0",
"@wordpress/data-controls": "4.35.0",
"@wordpress/dataviews": "10.2.0",
"@wordpress/date": "5.35.0",
"@wordpress/dom": "4.35.0",
"@wordpress/dom-ready": "^4.8.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ function wpcom_private_viewers_load_page() {
* Enqueue the Private Viewers assets.
*/
function wpcom_private_viewers_enqueue_assets() {
jetpack_mu_wpcom_enqueue_assets( 'private-viewers', array( 'js' ) );
jetpack_mu_wpcom_enqueue_assets( 'private-viewers', array( 'js', 'css' ) );
wp_add_inline_script(
'jetpack-mu-wpcom-private-viewers',
'var wpcomPrivateViewers = ' . wp_json_encode( array( 'siteId' => get_wpcom_blog_id() ) ) . ';',
'before'
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "@wordpress/dataviews/build-style/style.css";
Original file line number Diff line number Diff line change
@@ -1,20 +1,129 @@
import {
Card,
CardHeader,
CardBody,
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis
__experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis
} from '@wordpress/components';
import { DataViews, Field } from '@wordpress/dataviews';
import domReady from '@wordpress/dom-ready';
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { createRoot } from 'react-dom/client';
import wpcomRequest from 'wpcom-proxy-request';

import './private-viewers.scss';

type Viewer = {
ID: number;
login: string;
email: boolean | string;
name: string;
first_name: string;
last_name: string;
nice_name: string;
URL: string;
avatar_URL: string;
profile_URL: string;
ip_address: boolean | string;
};

declare global {
interface Window {
wpcomPrivateViewers: {
siteId: number;
};
}
}

const useViewers = () => {
const [ viewers, setViewers ] = useState< Viewer[] >( [] );
const [ totalViewers, setTotalViewers ] = useState< number >( 0 );

const fetchViewers = useCallback( async () => {
const path = addQueryArgs( `/sites/${ window.wpcomPrivateViewers.siteId }/viewers`, {
page: 1,
number: 2,
} );
const response: { viewers: Viewer[]; found: number } = await wpcomRequest( {
path,
apiVersion: '1.1',
} );
setViewers( response.viewers );
setTotalViewers( response.found );
}, [] );

useEffect( () => {
fetchViewers();
}, [ fetchViewers ] );

return {
viewers,
totalViewers,
};
};

const noop = () => {};

const getItemId = ( item: Viewer ) => item.ID.toString();

/**
* Private Viewers Component
*
* @return {JSX.Element} The component to render.
*/
function PrivateViewers() {
const { viewers, totalViewers } = useViewers();

const fields = useMemo< Field< Viewer >[] >(
() => [
{
id: 'nice_name',
label: __( 'Name', 'jetpack-mu-wpcom' ),
},
{
id: 'login',
label: __( 'Login', 'jetpack-mu-wpcom' ),
},
],
[]
);

return (
<div className="wrap">
<h1>{ __( 'Private Viewers', 'jetpack-mu-wpcom' ) }</h1>
<Card>
<CardHeader>
<Heading level={ 1 }>{ __( 'Private Viewers', 'jetpack-mu-wpcom' ) }</Heading>
<Text>{ __( 'Manage who can access your private site', 'jetpack-mu-wpcom' ) }</Text>
</CardHeader>
<CardBody>
<DataViews
data={ viewers }
fields={ fields }
view={ {
type: 'table',
search: '',
filters: [],
page: 1,
perPage: 2,
fields: [ 'nice_name', 'login' ],
} }
getItemId={ getItemId }
paginationInfo={ {
totalItems: totalViewers,
totalPages: Math.ceil( totalViewers / 2 ),
} }
onChangeView={ noop }
defaultLayouts={ { table: {} } }
/>
</CardBody>
</Card>
</div>
);
}

document.addEventListener( 'DOMContentLoaded', function () {
domReady( () => {
const container = document.getElementById( 'wpcom-private-viewers-root' );
if ( container ) {
const root = createRoot( container );
Expand Down