Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
94c38bb
feature: created modal for plugins network activation to select gover…
up1512001 Oct 24, 2025
0131813
feature: created required rest routes for multisite configurations
up1512001 Oct 24, 2025
fbdbe71
feature: auto api key updation and modal markup for governing site se…
up1512001 Oct 24, 2025
03fd03f
feature: created required helpers utils functions
up1512001 Oct 24, 2025
bb0f98b
chore: enqueue required js files and created constants for options
up1512001 Oct 24, 2025
e29b830
feature: created modal for adding multisite brand sites
up1512001 Oct 24, 2025
9313c19
chore: make existing pattern/template working consistent
up1512001 Oct 24, 2025
cc996b7
chore: remove site options on plugin deletion and updated pot file
up1512001 Oct 24, 2025
055e12d
address copilot feedbacks
up1512001 Oct 24, 2025
5b8175f
chore: updated governing site selection route and added required styl…
up1512001 Oct 24, 2025
c28171a
update: remove plugins script loading from network plugin screen
up1512001 Oct 24, 2025
d29c933
update: set api key for multisite governing site selection
up1512001 Oct 24, 2025
c5287e9
address copilot feedbacks
up1512001 Oct 24, 2025
e67eec7
chore: fix type case issue with id's of multisite
up1512001 Oct 24, 2025
ee43d7d
update: health check to allow same multisite requests
up1512001 Oct 27, 2025
4922ca8
feature: auto assign brand-site to new created sites in same MU
up1512001 Oct 27, 2025
37bd850
update: site details in governing site if its changes any how
up1512001 Oct 27, 2025
e60562f
feature: change document title same as modal
up1512001 Oct 27, 2025
56a2e83
update: patterns sharing message same as template sharing
up1512001 Oct 27, 2025
1b06592
feature: remove all options/posts on plugin network deletion
up1512001 Oct 27, 2025
83a3dde
update: translations file
up1512001 Oct 27, 2025
28e84f2
fix: patterns site tabs issue
up1512001 Oct 27, 2025
ee31113
chore: update brand site patterns tab and refactor code
up1512001 Oct 27, 2025
65b886e
fix: site_id type issue
up1512001 Oct 27, 2025
892d38a
chore: replace od prefix with onedesign
up1512001 Oct 27, 2025
aa99600
update: site_id type to be string only
up1512001 Oct 27, 2025
ab37226
fix: type mis-matching issue with id
up1512001 Oct 27, 2025
073eb70
address copilot feedbacks
up1512001 Oct 28, 2025
7d56343
fix: site type issue in template sharing
up1512001 Oct 28, 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
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"_": true,
"patternSyncData": true,
"TemplateLibraryData": true,
"OneDesignSettings": true
"OneDesignSettings": true,
"OneDesignMultiSiteSettings": true
},
"rules": {
"jsdoc/check-indentation": "error",
Expand Down
169 changes: 169 additions & 0 deletions assets/src/admin/multisite-plugin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/**
* WordPress dependencies
*/
import { useState, useEffect, createRoot, useCallback, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Card, CardHeader, CardBody, Notice, Button, SelectControl } from '@wordpress/components';

/**
* Global variable from PHP
*/
import { MULTISITES, API_NAMESPACE, NONCE } from '../../js/constants';

/**
* SiteTypeSelector component for selecting site type.
*
* @param {Object} props - Component properties.
* @param {string} props.value - Current selected value.
* @param {Function} props.setGoverningSite - Function to set governing site.
*
* @return {JSX.Element} Rendered component.
*/
const SiteTypeSelector = ( { value, setGoverningSite } ) => (
<SelectControl
label={ __( 'Select Governing Site', 'onedesign' ) }
value={ value }
help={ __( 'Choose governing site from current multisite network. Other sites will be set as brand sites. This setting cannot be changed later and affects available features and configurations.', 'onedesign' ) }
onChange={ ( v ) => {
setGoverningSite( v );
} }
options={ [
{ label: __( 'Select…', 'onedesign' ), value: '' },
...MULTISITES.map( ( site ) => ( { label: site.name, value: site.id } ) ),
] }
/>
);

/**
* Site type selection component for OneDesign Multisite setup.
*
* @return {JSX.Element} Rendered component.
*/
const OneDesignMultisiteGoverningSiteSelection = () => {
const [ governingSite, setGoverningSite ] = useState( '' );
const currentGoverningSiteID = useRef( '' );
const [ notice, setNotice ] = useState( null );
const [ isSaving, setIsSaving ] = useState( false );

const fetchCurrentGoverningSite = useCallback( async () => {
try {
const response = await fetch(
`${ API_NAMESPACE }/multisite/governing-site`,
{
headers: {
'Content-Type': 'application/json',
'X-WP-NONCE': NONCE,
},
},
);

if ( ! response.ok ) {
setNotice( {
type: 'error',
message: __( 'Error fetching current governing site.', 'onedesign' ),
} );
return;
}

const data = await response.json();
if ( data?.governing_site ) {
setGoverningSite( data.governing_site );
currentGoverningSiteID.current = data.governing_site;
}
return;
} catch {
setNotice( {
type: 'error',
message: __( 'Error fetching current governing site.', 'onedesign' ),
} );
}
}, [] );

useEffect( () => {
fetchCurrentGoverningSite();
}, [] ); // eslint-disable-line react-hooks/exhaustive-deps

const handleGoverningSiteChange = useCallback( async ( value ) => {
setGoverningSite( value );
currentGoverningSiteID.current = value;
setIsSaving( true );

try {
const response = await fetch( `${ API_NAMESPACE }/multisite/governing-site`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-NONCE': NONCE,
},
body: JSON.stringify( { governing_site_id: value } ),
} );

if ( ! response.ok ) {
setNotice( {
type: 'error',
message: __( 'Error setting governing site.', 'onedesign' ),
} );
setIsSaving( false );
return;
}

setNotice( {
type: 'success',
message: __( 'Governing site updated successfully.', 'onedesign' ),
} );

setTimeout( () => {
setIsSaving( false );
window.location.reload();
}, 1000 );
return;
} catch {
setNotice( {
type: 'error',
message: __( 'Error setting governing site.', 'onedesign' ),
} );
} finally {
setIsSaving( false );
}
}, [] );

return (
<>
<Card>
<>
{ notice?.message?.length > 0 &&
<Notice
status={ notice?.type ?? 'success' }
isDismissible={ true }
onRemove={ () => setNotice( null ) }
>
{ notice?.message }
</Notice>
}
</>
<CardHeader>
<h2>{ __( 'OneDesign', 'onedesign' ) }</h2>
</CardHeader>
<CardBody>
<SiteTypeSelector value={ governingSite } setGoverningSite={ setGoverningSite } />
<Button
variant="primary"
onClick={ () => handleGoverningSiteChange( governingSite ) }
disabled={ isSaving || governingSite.trim().length === 0 || governingSite === currentGoverningSiteID.current }
style={ { marginTop: '1.5rem' } }
isBusy={ isSaving }
>
{ __( 'Select Governing Site', 'onedesign' ) }
</Button>
</CardBody>
</Card>
</>
);
};

// Render to Gutenberg admin page with ID: onedesign-multisite-selection-modal
const target = document.getElementById( 'onedesign-multisite-selection-modal' );
if ( target ) {
const root = createRoot( target );
root.render( <OneDesignMultisiteGoverningSiteSelection /> );
}
12 changes: 5 additions & 7 deletions assets/src/admin/patterns/components/AppliedPatternsTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,9 @@ const AppliedPatternsTab = memo( ( {
variant="secondary"
isDestructive
disabled={ selectedPatternsToRemove.length === 0 || isRemoving }
isBusy={ isRemoving }
>
{ isRemoving
? __( 'Removing…', 'onedesign' )
: __( 'Remove Selected Patterns', 'onedesign' ) }
{ __( 'Remove Selected Patterns', 'onedesign' ) }
</Button>
</div>
</div>
Expand All @@ -222,10 +221,9 @@ const AppliedPatternsTab = memo( ( {
>
<div className="od-pattern-removal-modal-content">
<p>
{ __(
'Are you sure you want to remove the selected patterns? This action cannot be undone.',
'onedesign',
) }
{ __( 'Are you sure you want to remove selected patterns?', 'onedesign' ) }
<br />
{ __( 'Once you remove a pattern you won\'t be able to use it on brand sites, so please check and confirm you don\'t require it.', 'onedesign' ) }
</p>
<div className="od-pattern-removal-modal-actions">
<Button
Expand Down
6 changes: 2 additions & 4 deletions assets/src/admin/patterns/components/BasePatternsTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,9 @@ const BasePatternsTab = memo(
onClick={ handleApplyPatterns }
disabled={ isApplying || ! isSiteSelected }
className="od-apply-button"
isBusy={ isApplying }
>
{ isApplying && <Spinner /> }
{ isApplying
? __( 'Applying…', 'onedesign' )
: __( 'Apply Patterns', 'onedesign' ) }
{ __( 'Apply Patterns', 'onedesign' ) }
</Button>
) }
</div>
Expand Down
10 changes: 9 additions & 1 deletion assets/src/admin/settings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,15 @@ const OneDesignSettingsPage = () => {
}

{ siteType === 'governing-site' && (
<SiteTable sites={ sites } onEdit={ setEditingIndex } onDelete={ handleDelete } setFormData={ setFormData } setShowModal={ setShowModal } />
<SiteTable
sites={ sites }
onEdit={ setEditingIndex }
onDelete={ handleDelete }
setFormData={ setFormData }
setShowModal={ setShowModal }
setSites={ setSites }
setNotice={ setNotice }
/>
) }

{ showModal && (
Expand Down
Loading