Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BBMSK-12] Documentation #21

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 68 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# High-Level System Diagram

```mermaid
graph TD
A[index.js] --> B[SiteSettingsProvider]
B --> C[NavigationPanel]
B --> D[SettingsNotice]
B --> E[SettingsContainer]
E --> F[SettingsSnackbar]
E --> G[AddSettingPanel]

%% External Services
H[SettingsService - backbone.js] --> I[getSettings]
H --> J[saveSettings]
H --> K[addSetting]
H --> L[editSetting]
H --> M[deleteSetting]
H --> N[deleteAllSettings - not in use]

%% Styles and Hook
A --> O[useSettings Hook]
O --> P[fetchSettings]

%% Define styles
classDef component fill:#bbf,stroke:#333,stroke-width:2px;
classDef service fill:#f9f,stroke:#333,stroke-width:2px;
classDef hook fill:#cff,stroke:#333,stroke-width:2px;

%% Apply styles
class A,Q component;
class H service;
class O hook;
```

## Components

### SiteSettingsProvider

Provides context for the entire settings module and manages state and actions related to settings.

### Settings (Main Component)

Entry point of the settings module. Contains the following sub-components:
- **NavigationPanel**: Displays categories for navigation.
- **SettingsNotice**: Displays error notices.
- **SettingsContainer**: Displays settings fields for the selected category.
- **AddSettingPanel**: Provides a form to add new settings.
- **SettingsSnackbar**: Displays success notices in a snackbar format.

### NavigationPanel

Displays categories for navigation and allows switching between different categories.

### SettingsNotice

Displays error notices.

### SettingsContainer

Displays settings fields for the selected category and allows editing, saving, and deleting settings. Dynamically renders appropriate field components.

### AddSettingPanel

Provides a form to add new settings.

### SettingsSnackbar

Displays success notices in a snackbar format.
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Site Settings

This WordPress plugin provides an interface to create and manage global site settings
using supported components from the WordPress component library.

## Features

- Settings are split into three categories: General, Analytics, and Styles.
- Easily add, edit, and delete settings within each category.
- Configure new setting.
- Import / export setting (Upcoming)
- Use php function to retrieve value or arrtibutes for each setting (Upcoming)

## Local Development or Manual Install
Clone the repository into your `plugins` or `client-mu-plugins` directory.
```
Expand All @@ -25,3 +36,60 @@ Dev watch mode
```
npm run watch:dev
```

## Usage

1. Navigate to the "Site Settings" page in the WordPress admin panel.
2. Use the navigation panel to switch between different categories.
3. Add, edit, and delete settings as needed.
4. Save your changes or discard them if necessary.

## Architecture

View the current [architecture](ARCHITECTURE.md)

## Setting storage

Settings are stored in the `wp_options` table. This plugin uses backbone.js in `admin/services/settingServices` to fetch and save settings.

The setting are stored as JSON with the following structure:

```json
{
"supportedCategory": [
{
"id": "uniqueId",
"field": "supportedField",
"value": "value to be returned by API",
"attributes": { "object holding field props that can be spread on component, used as default values too" }
}
]
}
```

Supported categories (general, analytics and styles) as definded in `admin/schema/supportedCategories`

Supported fields (text, toggle, radio and checkbox-group) definded in `admin/fields/supportedFields`

## Settings validation

When reading settings from db or about to save setting we validate using `admin/schema/settingSchema`. If this validation fails a notice will be displayed on top of the main settings view.


## Add new supported field

1. Add to `admin/fields/supported-fields` Following this structure:
```js
<key>: {
Component: <Custom | Wordpress component>,
keyProp: <Value prop for component E.G checked | value>,
label: <Used in select dropdown>
attributes: <Props that can be easily spread on component>
}
```
2. Check for the new field in `admin/components/FieldConfigurator` and add your own custom field configurator to handle creating new fields.
3. Handle updating the props. When saving (submitting the form), it will be passed to `admin/schema/formatSetting` and then to the provider, which will validate the settings before saving to the database.
4. Update the `getSettingValue` function in `admin/schema/formatSetting` for the new field.
5. Ensure the new field can be read and updated in admin/components/SettingsContainer where settings stored in the database are fetched on mount.


8 changes: 7 additions & 1 deletion package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
"@wordpress/element": "^6.0.0",
"@wordpress/i18n": "^5.3.0",
"@wordpress/icons": "^10.3.0",
"lodash": "^4.17.21",
"@wordpress/notices": "^5.3.0",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"uuid": "^10.0.0"
}
}
8 changes: 1 addition & 7 deletions src/admin/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {

const Settings = () => {
const [ activeCategory, setActiveCategory ] = useState( 'General' );
const [ showAddPanel, setShowAddPanel ] = useState( false );

const { fetchSettings } = useSettings();

Expand All @@ -26,17 +25,12 @@ const Settings = () => {
<NavigationPanel
activeCategory={ activeCategory }
setActiveCategory={ setActiveCategory }
showAddPanel={ () => setShowAddPanel( true ) }
/>
<div className="settings">
<SettingsNotice />
<SettingsContainer category={ activeCategory } />
</div>
{ showAddPanel && (
<AddSettingPanel
handleClose={ () => setShowAddPanel( false ) }
/>
) }
<AddSettingPanel />
<SettingsSnackbar />
</>
);
Expand Down
133 changes: 80 additions & 53 deletions src/admin/components/AddSettingPanel.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Button, SelectControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { close, plus } from '@wordpress/icons';

import FieldConfigurator from './FieldConfigurator';
import { useSettings } from '../hooks';
import { getSelectSupportedOptions } from '../fields';
import { formatSetting, getSelectSupportedCategoriesOptions } from '../schema';

const AddSettingPanel = ( { handleClose } ) => {
const AddSettingPanel = () => {
const { loading, handleAddSetting } = useSettings();
const [ category, setCategory ] = useState( 'general' );
const [ field, setField ] = useState( 'text' );
const [ newSetting, setNewSetting ] = useState( null );
const [ showAddPanel, setShowAddPanel ] = useState( false );

const categoryOptions = getSelectSupportedCategoriesOptions();
const fieldOptions = getSelectSupportedOptions();
Expand Down Expand Up @@ -47,62 +49,87 @@ const AddSettingPanel = ( { handleClose } ) => {
};

return (
<div className="add-settings-panel">
<div className="add-settings-panel__header">
<h2>{ __( 'Add Settings', 'bb_site_settings' ) }</h2>
<Button
aria-label={ __(
'Close add setting panel',
'bb_site_settings'
) }
icon="no-alt"
onClick={ handleClose }
/>
</div>
<form className="add-setting-panel__form" onSubmit={ handleSubmit }>
<div className="add-settings-panel__body">
<SelectControl
className="form-field--required"
options={ categoryOptions }
value={ category }
onChange={ ( selected ) => setCategory( selected ) }
label="Category"
required
/>
<>
{ showAddPanel && (
<div className="add-settings-panel">
<div className="add-settings-panel__header">
<h2>{ __( 'Add Settings', 'bb_site_settings' ) }</h2>
<Button
label={ __(
'Close add setting sidebar',
'bb_site_settings'
) }
tooltipPosition="middle left"
icon={ close }
onClick={ () => setShowAddPanel( false ) }
/>
</div>
<form
className="add-setting-panel__form"
onSubmit={ handleSubmit }
>
<div className="add-settings-panel__body">
<SelectControl
className="form-field--required"
options={ categoryOptions }
value={ category }
onChange={ ( selected ) =>
setCategory( selected )
}
label="Category"
required
/>

<SelectControl
className="form-field--required"
options={ fieldOptions }
value={ field }
onChange={ ( selected ) => setField( selected ) }
label="Field"
required
/>
<SelectControl
className="form-field--required"
options={ fieldOptions }
value={ field }
onChange={ ( selected ) =>
setField( selected )
}
label="Field"
required
/>

<FieldConfigurator
field={ field }
setting={ newSetting }
setNewSetting={ setNewSetting }
/>
</div>
<FieldConfigurator
field={ field }
setting={ newSetting }
setNewSetting={ setNewSetting }
/>
</div>

<div className="add-settings-panel__footer">
<Button
aria-label={ __(
'Save new setting',
'bb_site_settings'
) }
type="submit"
variant="primary"
disabled={ loading || ! isFormValid() }
aria-busy={ loading }
isBusy={ loading }
>
{ __( 'Save', 'bb_site_settings' ) }
</Button>
<div className="add-settings-panel__footer">
<Button
label={ __(
'Save new setting',
'bb_site_settings'
) }
type="submit"
variant="primary"
disabled={ loading || ! isFormValid() }
aria-busy={ loading }
isBusy={ loading }
>
{ __( 'Save', 'bb_site_settings' ) }
</Button>
</div>
</form>
</div>
</form>
</div>
) }
{ ! showAddPanel && (
<Button
className="add-setting__fab"
label={ __(
'Open add setting sidebar',
'bb_site_settings'
) }
tooltipPosition="middle left"
variant="primary"
icon={ plus }
onClick={ () => setShowAddPanel( true ) }
/>
) }
</>
);
};

Expand Down
Loading