Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
135113b
chore: initial template sharing
up1512001 Sep 26, 2025
c87975d
update: template removal
up1512001 Sep 29, 2025
ad01dec
feature: sync shared templates
up1512001 Sep 30, 2025
38a3c6f
feature: added synced pattern to template sharing
up1512001 Oct 1, 2025
8a0d220
fix: linting & phpcs issues
up1512001 Oct 3, 2025
fb363ec
chore: code cleanup & added permission check
up1512001 Oct 6, 2025
a851884
fix: copilot review
up1512001 Oct 6, 2025
3793f3e
update: added missing i18n
up1512001 Oct 6, 2025
a89f4c3
remove: theme option from template part
up1512001 Oct 6, 2025
d5a619a
fix: theme issue of template part
up1512001 Oct 6, 2025
00b8078
update: synced patterns endpoint
up1512001 Oct 6, 2025
e0645f5
fix: templates post type issue
up1512001 Oct 7, 2025
975bc14
fix: plugin checker issue of release workflow
up1512001 Oct 7, 2025
a85e88d
update: template part creation
up1512001 Oct 7, 2025
054ab4e
Merge branch 'main' into chore/template
up1512001 Oct 7, 2025
5e8c377
chore: added js doc comments
up1512001 Oct 7, 2025
6ca4baa
fix: typo
up1512001 Oct 7, 2025
42dd0e8
fix: package inconsistency
up1512001 Oct 7, 2025
2a321e5
update: autoloaded options to false
up1512001 Oct 7, 2025
5520b15
fix: QA issues
up1512001 Oct 7, 2025
0452ff9
chore: added i18n to missing strings
up1512001 Oct 7, 2025
5321d3a
update: templates sharing success message
up1512001 Oct 7, 2025
7c8b970
update: close modal after successfully sharing template
up1512001 Oct 8, 2025
3cb65ef
chore: added missing sanitization
up1512001 Oct 9, 2025
42d4279
remove: post meta associated with posts created for templates
up1512001 Oct 9, 2025
fcd6932
update: assets creation
up1512001 Oct 9, 2025
f7d4888
chore: refactor site selection for template sharing
up1512001 Oct 9, 2025
85ba088
remove: cache flushing logic
up1512001 Oct 9, 2025
baf93a4
fix: code issues & unify utils and constants usage
up1512001 Oct 13, 2025
3588949
update: setting link same as template sharing
up1512001 Oct 13, 2025
f80060b
chore: refactor code for patterns sharing
up1512001 Oct 13, 2025
3e8672b
feature: added site mode selection modal on plugin activation
up1512001 Oct 13, 2025
5febb73
feature: converted PHP settings to gutenberg components
up1512001 Oct 13, 2025
9e5661c
remove: dead code
up1512001 Oct 13, 2025
5627c95
feature: created separate class for handling api key
up1512001 Oct 13, 2025
7c09f16
feature: created required routes for gutenberg settings page
up1512001 Oct 13, 2025
a864930
chore: refactor code base and improve code quality
up1512001 Oct 13, 2025
a7a8350
chore: added missing doc comments
up1512001 Oct 13, 2025
0419012
chore: remove dashboard/consumer reference from whole code
up1512001 Oct 13, 2025
82863e7
update: media script loading to only governing site
up1512001 Oct 14, 2025
e3ec439
fix: copilot review
up1512001 Oct 14, 2025
3518cc2
feature: added warning if site is not reachable
up1512001 Oct 15, 2025
58c650c
chore: addredd PR feedback
up1512001 Oct 15, 2025
d72fcbd
fix: formatting issue
up1512001 Oct 15, 2025
831a020
update: site selection for disabled/unreachable sites
up1512001 Oct 15, 2025
613841c
chore: addredd PR feedback
up1512001 Oct 16, 2025
0ef6e48
fix: caching issues
up1512001 Oct 16, 2025
ea38d18
chore: rename design library reference with pattern library
up1512001 Oct 16, 2025
6f279a4
feature: created re-usable hook for sites health check info
up1512001 Oct 16, 2025
d12b708
chore: addredd PR feedback
up1512001 Oct 17, 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
4 changes: 3 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
},
"globals": {
"_": true,
"patternSyncData": true
"patternSyncData": true,
"TemplateLibraryData": true,
"OneDesignSettings": true
},
"rules": {
"jsdoc/check-indentation": "error",
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release_on_tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ jobs:
cp composer.json /tmp/onedesign/
cp -r inc/ /tmp/onedesign/
cp onedesign.php /tmp/onedesign/
cp README.md /tmp/onedesign/
cp readme.txt /tmp/onedesign/
cp -r vendor/ /tmp/onedesign/
cp uninstall.php /tmp/onedesign/
cp -r languages/ /tmp/onedesign/

# Create the zip file
cd /tmp
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
![Banner V3](https://rtcamp.com/wp-content/uploads/sites/2/2024/09/OneDesign-Banner.png)
![Banner V3](./assets/images/banner.webp)

# OneDesign
Contributors: [rtcamp](https://profiles.wordpress.org/rtcamp), [parthnvaswani](https://github.com/parthnvaswani), [up1512001](https://github.com/up1512001), [singhakanshu00](https://github.com/singhakanshu00), [danish17](https://github.com/danish17), [aviral-mittal](https://github.com/aviral-mittal), [vaishaliagola27](https://github.com/vaishaliagola27), [rishavjeet](https://github.com/rishavjeet), [vishal4669](https://github.com/vishal4669), [iamimmanuelraj](https://github.com/iamimmanuelraj)
Contributors: [rtcamp](https://profiles.wordpress.org/rtcamp), [parthnvaswani](https://github.com/parthnvaswani), [up1512001](https://github.com/up1512001), [singhakanshu00](https://github.com/singhakanshu00), [danish17](https://github.com/danish17), [aviral-mittal](https://github.com/aviral-mittal), [vaishaliagola27](https://github.com/vaishaliagola27), [rishavjeet](https://github.com/rishavjeet), [vishal4669](https://github.com/vishal4669), [iamimmanuelraj](https://github.com/iamimmanuelraj) [vishalkakadiya](https://github.com/vishalkakadiya)

Tags: OnePress, Pattern distribution, Pattern sync, OneDesign, WordPress multisite, WordPress network, Gutenberg, WordPress Site Editor, Block Patterns, Pattern management, WordPress plugin, Design consistency, Pattern library

Expand All @@ -12,7 +12,7 @@ This plugin is licensed under the GPL v2 or later.
This tool enables synchronization of block patterns across multiple sites in a WordPress multisite network.

## Description
OneDesign allows you to define patterns on a Dashboard site and apply them to consumer sites, maintaining consistency across your network. The plugin provides an intuitive interface for browsing, searching, and applying patterns, making it easy to maintain design consistency across all your network sites.
OneDesign allows you to define patterns on a Governing site and apply them to brand sites, maintaining consistency across your network. The plugin provides an intuitive interface for browsing, searching, and applying patterns, making it easy to maintain design consistency across all your network sites.

## Why OneDesign?
Managing multiple websites—whether for different brands, regions, or languages shouldn’t mean reinventing the wheel each time. Instead of designing layouts from scratch for each site, OneDesign lets you create once and deploy anywhere, in just one click.
Expand Down Expand Up @@ -43,7 +43,7 @@ Built for enterprise teams, OneDesign unifies your design, editorial, and develo

- **Pattern Status Monitoring**: Track deployment success and synchronization across all connected sites

- **Multisite Pattern Sync**: Define patterns on the dashboard site and apply to multiple consumer sites
- **Multisite Pattern Sync**: Define patterns on the governing site and apply to multiple brand sites

- **Pattern Management**: View and manage already applied patterns

Expand All @@ -64,19 +64,19 @@ Built for enterprise teams, OneDesign unifies your design, editorial, and develo

## How It Works

### Setting Up Dashboard and Consumer Sites
### Setting Up Governing and Brand Sites
1. Install and activate the OneDesign plugin on all sites in your network
2. From the OneDesign settings, designate one site as the “Dashboard Site” (source of patterns)
3. Designate all other sites as “Consumer Sites” (where patterns will be applied)
4. Copy the API keys generated for each Consumer Site from their respective settings pages
5. In the Dashboard Site settings, register each Consumer Site by adding:
2. From the OneDesign settings, designate one site as the “Governing Site” (source of patterns)
3. Designate all other sites as “Brand Sites” (where patterns will be applied)
4. Copy the API keys generated for each Brand Site from their respective settings pages
5. In the Governing Site settings, register each Brand Site by adding:
- Site name
- URL
- Logo
- API key

### Accessing the Pattern Library
1. On your Dashboard Site, access the Design Library from the sidebar menu
1. On your Governing Site, access the Pattern Library from the sidebar menu
2. This opens a full-page interface showing all available patterns
3. Patterns are organized by categories with vertical tabs for your registered sites

Expand Down Expand Up @@ -113,15 +113,15 @@ For development guidelines, please refer to our [Development Guide](./docs/DEVEL
### How are patterns transferred between sites?
Patterns are transferred securely via WordPress REST API, ensuring that all pattern data, including blocks and settings, are properly synchronized.
### Can I customize which patterns are available to specific sites?
Yes, you can control which patterns are applied to each consumer site by managing the selections in the Design Library.
Yes, you can control which patterns are applied to each brand site by managing the selections in the Pattern Library.
### Are there any limits to how many patterns I can sync?
There are no hard limits on the number of patterns you can sync, but performance may vary depending on your server resources and the complexity of the patterns.
### Can I also remove patterns from specific sites?
Yes. You are able to do that from the dashboard itself.

### Troubleshooting
1. **Patterns not showing up in the library**
- Ensure your dashboard site is correctly set up
- Ensure your governing site is correctly set up
- Check network connectivity between sites
- Verify REST API permissions
2. **Search not working correctly**
Expand Down
Binary file added assets/images/banner.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { registerPlugin } from '@wordpress/plugins';
/**
* Internal dependencies
*/
import LibraryModal from './LibraryModal';
import PatternModal from './components/PatternModal';

/**
* Registers the Pattern Sync Library plugin.
Expand All @@ -30,6 +30,6 @@ registerPlugin( 'onedesign-library', {
const modalWrap = document.createElement( 'div' );
const modal = Object.assign( modalWrap, { id: modalID, className } );
document.body?.appendChild( modal );
createRoot( modal ).render( <LibraryModal /> );
createRoot( modal ).render( <PatternModal /> );
},
} );
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,19 @@ import MemoizedPatternPreview from './MemoizedPatternPreview';
/**
* AppliedPatternsTab component displays a list of applied patterns with options to remove them.
*
* @param {Object} props - Component properties.
* @param {boolean} props.isLoadingApplied - Indicates if applied patterns are loading.
* @param {Array} props.appliedPatterns - List of applied patterns.
* @param {number} props.visibleAppliedCount - Number of applied patterns currently visible.
* @param {Array} props.selectedPatterns - List of selected patterns (not used in this component).
* @param {boolean} props.hasMoreAppliedPatterns - Indicates if there are more applied patterns to load (not used in this component).
* @param {Function} props.loadMoreAppliedPatterns - Function to load more applied patterns (not used in this component).
* @param {Function} props.applySelectedPatterns - Function to apply selected patterns.
* @param {Function} props.setVisibleAppliedCount - Function to set the number of visible applied patterns.
* @param {Object} props.siteInfo - Information about the site (used for applying patterns).
* @param {Object} props - Component properties.
* @param {boolean} props.isLoadingApplied - Indicates if applied patterns are loading.
* @param {Array} props.appliedPatterns - List of applied patterns.
* @param {number} props.visibleAppliedCount - Number of applied patterns currently visible.
* @param {Function} props.applySelectedPatterns - Function to apply selected patterns.
* @param {Function} props.setVisibleAppliedCount - Function to set the number of visible applied patterns.
* @param {Object} props.siteInfo - Information about the site (used for applying patterns).
* @return {JSX.Element} Rendered component.
*/
const AppliedPatternsTab = memo( ( {
isLoadingApplied,
appliedPatterns,
visibleAppliedCount,
selectedPatterns, // eslint-disable-line no-unused-vars
hasMoreAppliedPatterns, // eslint-disable-line no-unused-vars
loadMoreAppliedPatterns, // eslint-disable-line no-unused-vars
applySelectedPatterns,
setVisibleAppliedCount,
siteInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { Button, Modal, Spinner, Notice } from '@wordpress/components';
* Internal dependencies
*/
import MemoizedPatternPreview from './MemoizedPatternPreview';
import RenderConsumerSiteMeta from '../../plugins/consumer-site';
import SiteSelection from './SiteSelection';

/**
* BasePatternsTab component displays a list of base patterns with options to apply them to consumer sites
* BasePatternsTab component displays a list of base patterns with options to apply them to brand sites
*
* @param {Object} props - Component properties.
* @param {boolean} props.isLoading - Indicates if base patterns are loading.
Expand All @@ -24,7 +24,7 @@ import RenderConsumerSiteMeta from '../../plugins/consumer-site';
* @param {Function} props.loadMorePatterns - Function to load more base patterns.
* @param {Function} props.applySelectedPatterns - Function to apply selected patterns.
* @param {Function} props.setSelectedPatterns - Function to set the selected patterns.
* @param {Object} props.sitePatterns - Patterns from the consumer site.
* @param {Object} props.sitePatterns - Patterns from the brand site.
* @return {JSX.Element} Rendered component.
*/
const BasePatternsTab = memo(
Expand Down Expand Up @@ -66,7 +66,7 @@ const BasePatternsTab = memo(
);
}

const openConsumerSiteModal = () => {
const OpenBrandSiteModal = () => {
if ( selectedPatterns.length === 0 ) {
setApplicationStatus( {
type: 'warning',
Expand All @@ -82,7 +82,7 @@ const BasePatternsTab = memo(
setIsModalOpen( true );
};

const closeConsumerSiteModal = () => {
const CloseBrandSiteModal = () => {
// If we're in the middle of applying patterns, show confirmation first
if ( isApplying && ! showCloseConfirmation ) {
setShowCloseConfirmation( true );
Expand All @@ -104,10 +104,6 @@ const BasePatternsTab = memo(

const handleApplyPatterns = async () => {
setIsApplying( true );
setApplicationStatus( {
type: 'info',
message: __( 'Applying patterns to selected sites…', 'onedesign' ),
} );

try {
const result = await applySelectedPatterns();
Expand All @@ -121,8 +117,9 @@ const BasePatternsTab = memo(

// Close modal after success with slightly longer delay for better user feedback
setTimeout( () => {
closeConsumerSiteModal();
}, 2000 );
CloseBrandSiteModal();
setSelectedPatterns( [] );
}, 3000 );
} else {
setApplicationStatus( {
type: 'error',
Expand Down Expand Up @@ -178,52 +175,29 @@ const BasePatternsTab = memo(
}
};

const consumerSiteSelection = () => {
const BrandSiteSelection = () => {
return (
<div className="od-consumer-site-modal-content">
<div className="od-site-selection-wrapper">
<RenderConsumerSiteMeta
setIsSiteSelected={ setIsSiteSelected }
selectedPatterns={ selectedPatterns }
basePatterns={ basePatterns }
sitePatterns={ sitePatterns }
/>
</div>
<div className="od-brand-site-modal-content">

{ applicationStatus && (
<Notice
status={ applicationStatus.type }
isDismissible={ false }
status={ applicationStatus?.type ?? 'info' }
isDismissible={ true }
className="od-application-notice od-error-notice"
>
<div className="od-error-notice-summary">
<div className="od-notice-message">
{ applicationStatus.message }
{ applicationStatus?.message }
</div>

{ applicationStatus.hasDetails && (
<button
type="button"
className="od-error-notice-toggle"
onClick={ () => setShowDetailedErrors( ( prev ) => ! prev ) }
>
{ showDetailedErrors
? __( 'Hide Details', 'onedesign' )
: __( 'Show Details', 'onedesign' ) }
<span className="od-toggle-icon">
{ showDetailedErrors ? '▲' : '▼' }
</span>
</button>
) }
</div>

{ showDetailedErrors && applicationStatus.hasDetails && (
{ showDetailedErrors && applicationStatus?.hasDetails && (
<div className="od-error-details">
{ detailedErrors.map( ( error, index ) => (
<div key={ index } className="od-error-site">
<div className="od-error-site-name">{ error.site }</div>
<div className="od-error-site-name">{ error?.site }</div>
<div className="od-error-site-message">
{ error.message }
{ error?.message }
</div>
</div>
) ) }
Expand All @@ -232,10 +206,19 @@ const BasePatternsTab = memo(
</Notice>
) }

<div className="od-site-selection-wrapper">
<SiteSelection
setIsSiteSelected={ setIsSiteSelected }
selectedPatterns={ selectedPatterns }
basePatterns={ basePatterns }
sitePatterns={ sitePatterns }
/>
</div>

<div className="od-modal-actions">
<Button
variant="secondary"
onClick={ closeConsumerSiteModal }
onClick={ CloseBrandSiteModal }
disabled={ isApplying && ! showCloseConfirmation }
>
{ showCloseConfirmation
Expand Down Expand Up @@ -325,7 +308,7 @@ const BasePatternsTab = memo(
) }

<Button
onClick={ openConsumerSiteModal }
onClick={ OpenBrandSiteModal }
variant="primary"
className="od-apply-to-sites-button"
disabled={ selectedPatterns.length === 0 }
Expand All @@ -340,13 +323,13 @@ const BasePatternsTab = memo(
{ isModalOpen && (
<Modal
title=""
onRequestClose={ closeConsumerSiteModal }
className="od-consumer-site-modal"
onRequestClose={ CloseBrandSiteModal }
className="od-brand-site-modal"
shouldCloseOnClickOutside={ ! isApplying }
shouldCloseOnEsc={ ! isApplying }
isFullScreen={ true }
>
{ consumerSiteSelection() }
{ BrandSiteSelection() }
</Modal>
) }
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* WordPress dependencies
*/
import { useState, useEffect, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import { __ } from '@wordpress/i18n';
import { parse } from '@wordpress/blocks';
import { BlockPreview } from '@wordpress/block-editor';

// Separate memoized component for the preview
/**
* Pattern content preview.
*
* @param {Object} props - Component properties.
* @param {Array} props.parsedBlocks - Parsed blocks to preview.
* @return {JSX.Element} Rendered component.
*/
const PatternPreviewContent = memo( ( { parsedBlocks } ) => {
return (
<div className="od-pattern-preview">
Expand All @@ -16,7 +22,13 @@ const PatternPreviewContent = memo( ( { parsedBlocks } ) => {
);
} );

// Separate memoized component for pattern categories
/**
* Separate memoized component for pattern categories
*
* @param {Object} props - Component properties.
* @param {Object} props.categories - Categories object.
* @return {JSX.Element} Rendered component.
*/
const PatternCategories = memo( ( { categories } ) => {
if ( ! categories || typeof categories !== 'object' || Array.isArray( categories ) ) {
return null;
Expand All @@ -40,7 +52,13 @@ const PatternCategories = memo( ( { categories } ) => {
);
} );

// Separate memoized component for provider site
/**
* Separate memoized component for provider site info
*
* @param {Object} props - Component properties.
* @param {string} props.providerSite - Provider site name.
* @return {JSX.Element} Rendered component.
*/
const ProviderSiteInfo = memo( ( { providerSite } ) => {
if ( ! providerSite ) {
return null;
Expand Down
Loading