├── .prettierrc ├── .wp-env.json ├── .vscode └── settings.json ├── src ├── index.js ├── style.scss └── components │ ├── Panel.js │ └── SettingsPage.js ├── readme.txt ├── .editorconfig ├── .gitignore ├── package.json ├── example-wp-settings.php ├── .stylelintrc.json ├── readme.md └── inc └── class-example-wp-settings.php /.prettierrc: -------------------------------------------------------------------------------- 1 | "@wordpress/prettier-config" 2 | -------------------------------------------------------------------------------- /.wp-env.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["."] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[scss]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { createRoot } from '@wordpress/element'; 2 | import SettingsPage from './components/SettingsPage'; 3 | 4 | import './style.scss'; 5 | 6 | let root = createRoot( document.getElementById( 'root' ) ); 7 | root.render( ); 8 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Example WP Settings === 2 | Contributors: bacoords 3 | Tags: block 4 | Tested up to: 6.1 5 | Stable tag: 0.1.0 6 | License: GPL-2.0-or-later 7 | License URI: https://www.gnu.org/licenses/gpl-2.0.html 8 | 9 | Example settings page scaffolded with Create Block tool. 10 | -------------------------------------------------------------------------------- /src/style.scss: -------------------------------------------------------------------------------- 1 | .example-wp-settings { 2 | max-width: 780px; 3 | h1 { 4 | text-align: center; 5 | } 6 | .example-wp-settings-tab-panel { 7 | .components-tab-panel__tabs { 8 | justify-content: center; 9 | border-bottom: 1px solid #ddd; 10 | } 11 | } 12 | 13 | .example-wp-settings-field-group { 14 | margin-top: 2rem; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | 16 | [*.{yml,yaml}] 17 | indent_style = space 18 | indent_size = 2 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Coverage directory used by tools like istanbul 9 | coverage 10 | 11 | # Compiled binary addons (https://nodejs.org/api/addons.html) 12 | build/Release 13 | 14 | # Dependency directories 15 | node_modules/ 16 | 17 | # Optional npm cache directory 18 | .npm 19 | 20 | # Optional eslint cache 21 | .eslintcache 22 | 23 | # Output of `npm pack` 24 | *.tgz 25 | 26 | # Output of `wp-scripts plugin-zip` 27 | *.zip 28 | 29 | # dotenv environment variables file 30 | .env 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-wp-settings", 3 | "version": "0.1.0", 4 | "description": "Example WordPress settings page.", 5 | "author": "The WordPress Contributors", 6 | "license": "GPL-2.0-or-later", 7 | "main": "build/index.js", 8 | "scripts": { 9 | "build": "wp-scripts build", 10 | "format": "wp-scripts format", 11 | "lint:css": "wp-scripts lint-style", 12 | "lint:js": "wp-scripts lint-js", 13 | "packages-update": "wp-scripts packages-update", 14 | "plugin-zip": "wp-scripts plugin-zip", 15 | "start": "wp-scripts start", 16 | "env": "wp-env" 17 | }, 18 | "devDependencies": { 19 | "@wordpress/scripts": "^26.17.0" 20 | }, 21 | "dependencies": { 22 | "@wordpress/env": "^8.12.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example-wp-settings.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | ## Development 9 | 10 | This plugin was scaffolded with [@wordpress/create-block](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/). If you'd like to develop from this repository, first install all of the dependencies: 11 | 12 | `npm install` 13 | 14 | Then run the build process in a watch mode: 15 | 16 | `npm start` 17 | 18 | ## Running Locally 19 | 20 | To use the included local environment, make sure Docker is running and then run the following command: 21 | 22 | `npm run env start` 23 | 24 | and visit [http://localhost:8888/wp-admin](http://localhost:8888/wp-admin). 25 | 26 | You should be able to log in with Username: `admin` and Password: `password`. 27 | 28 | [Learn more about wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/). 29 | -------------------------------------------------------------------------------- /src/components/Panel.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { Flex, FlexItem, TextControl } from '@wordpress/components'; 3 | 4 | import { useDispatch, useSelect } from '@wordpress/data'; 5 | import { store as coreStore } from '@wordpress/core-data'; 6 | 7 | function Panel() { 8 | // Get the settings from the store. 9 | const { record: settings, hasResolved } = useSelect( ( select ) => { 10 | return { 11 | record: select( coreStore ).getEditedEntityRecord( 'root', 'site' ), 12 | hasResolved: select( coreStore ).hasFinishedResolution( 13 | 'getEditedEntityRecord', 14 | [ 'root', 'site' ] 15 | ), 16 | }; 17 | } ); 18 | 19 | // We'll use these functions to save the settings to the store. 20 | const { editEntityRecord } = useDispatch( coreStore ); 21 | 22 | if ( ! hasResolved ) { 23 | return null; 24 | } 25 | 26 | // This will save settings the settings to the local state only. 27 | const updateOptions = ( key, value ) => { 28 | editEntityRecord( 'root', 'site', undefined, { 29 | wpdev_account_settings: { 30 | ...settings.wpdev_account_settings, 31 | [ key ]: value, 32 | }, 33 | } ); 34 | }; 35 | 36 | return ( 37 | 42 | 43 | { 48 | updateOptions( 'account_number', value ); 49 | } } 50 | /> 51 | 52 | 53 | { 58 | updateOptions( 'account_key', value ); 59 | } } 60 | /> 61 | 62 | 63 | ); 64 | } 65 | 66 | export default Panel; 67 | -------------------------------------------------------------------------------- /src/components/SettingsPage.js: -------------------------------------------------------------------------------- 1 | import { __ } from '@wordpress/i18n'; 2 | import { useState, useEffect } from '@wordpress/element'; 3 | import { 4 | Card, 5 | CardBody, 6 | CardDivider, 7 | Flex, 8 | FlexItem, 9 | Button, 10 | Snackbar, 11 | TabPanel, 12 | } from '@wordpress/components'; 13 | 14 | import { useDispatch, useSelect } from '@wordpress/data'; 15 | import { store as coreStore } from '@wordpress/core-data'; 16 | 17 | import Panel from './Panel'; 18 | 19 | function SettingsPage() { 20 | // Get the settings from the store. 21 | const { record: settings, hasResolved } = useSelect( ( select ) => { 22 | return { 23 | record: select( coreStore ).getEditedEntityRecord( 'root', 'site' ), 24 | hasResolved: select( coreStore ).hasFinishedResolution( 25 | 'getEditedEntityRecord', 26 | [ 'root', 'site' ] 27 | ), 28 | }; 29 | } ); 30 | 31 | // We'll use these functions to save the settings to the store. 32 | const { saveEntityRecord } = useDispatch( coreStore ); 33 | 34 | // State to show a success message when the settings are saved. 35 | const [ success, setSuccess ] = useState( false ); 36 | 37 | // State to keep track of which tab is active. 38 | const [ activeTab, setActiveTab ] = useState( 'panel' ); 39 | 40 | // If the settings haven't been loaded yet, we'll return null. 41 | // This needs to happen after all the hooks are called. 42 | if ( ! hasResolved ) { 43 | return null; 44 | } 45 | // In the block editor, saving to the database happens automatically when you publish or update a post. 46 | // In the our settings page, you would need to add a separate button to save the settings. 47 | const saveOptions = ( event ) => { 48 | event.preventDefault(); 49 | saveEntityRecord( 'root', 'site', { 50 | wpdev_account_settings: settings.wpdev_account_settings, 51 | } ).then( ( response ) => { 52 | setSuccess( true ); 53 | console.log( response ); 54 | } ); 55 | }; 56 | 57 | return ( 58 |
59 | 60 | 61 |

{ __( 'Example WP Settings Settings' ) }

62 | { 65 | setActiveTab( tabName ); 66 | } } 67 | initialTabName={ activeTab } 68 | tabs={ [ 69 | { 70 | name: 'panel', 71 | title: 'Example Panel', 72 | content: , 73 | }, 74 | ] } 75 | > 76 | { ( tab ) => <>{ tab.content } } 77 | 78 |
79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | { success && ( 89 | 96 | Saved 97 | 98 | ) } 99 | 100 | 101 | 102 |
103 |
104 | ); 105 | } 106 | 107 | export default SettingsPage; 108 | -------------------------------------------------------------------------------- /inc/class-example-wp-settings.php: -------------------------------------------------------------------------------- 1 | 59 |
60 |
61 |
62 | id ) { 77 | return; 78 | } 79 | 80 | // Enqueue the styles for the core components library. 81 | wp_enqueue_style( 'global' ); 82 | wp_enqueue_style( 'wp-edit-post' ); 83 | 84 | // Our build processs generates a `index.asset.php` file for each entry point. 85 | $asset_file = include EXAMPLE_WP_SETTINGS_PATH . '/build/index.asset.php'; 86 | 87 | // Enqueue the admin page script and its dependencies. 88 | wp_enqueue_script( 'example-wp-settings-admin-page', EXAMPLE_WP_SETTINGS_URL . '/build/index.js', $asset_file['dependencies'], $asset_file['version'], true ); 89 | 90 | // Enqueue the admin page styles. 91 | wp_enqueue_style( 'example-wp-settings-admin-page', EXAMPLE_WP_SETTINGS_URL . '/build/style-index.css', array(), $asset_file['version'] ); 92 | } 93 | 94 | 95 | 96 | 97 | 98 | /** 99 | * Register our custom settings handler. 100 | * 101 | * @return void 102 | */ 103 | public static function register_custom_settings() { 104 | 105 | // Register our custom setting. 106 | register_setting( 107 | 'wpdev', 108 | 'wpdev_account_settings', 109 | array( 110 | 'type' => 'object', // Our setting is an object that could contain multiple values. 111 | 'description' => 'Account Settings for our API.', 112 | 'sanitize_callback' => array( get_class(), 'sanitize_callback' ), 113 | 'default' => array( // Default values for our setting. 114 | 'account_number' => '', 115 | 'account_key' => '', 116 | ), 117 | 'show_in_rest' => array( 118 | 'schema' => array( 119 | 'type' => 'object', 120 | 'properties' => array( 121 | 'account_number' => array( // Schema for our 'account_number'. 122 | 'type' => 'string', 123 | ), 124 | 'account_key' => array( // Schema for our 'account_key'. 125 | 'type' => 'string', 126 | ), 127 | ), 128 | ), 129 | ), 130 | ) 131 | ); 132 | } 133 | 134 | 135 | /** 136 | * Sanitize our settings. 137 | * 138 | * @param array $settings The settings to sanitize. 139 | * @return array 140 | */ 141 | public static function sanitize_callback( $settings ) { 142 | // Sanitize our 'account_number'. 143 | $settings['account_number'] = sanitize_text_field( $settings['account_number'] ); 144 | // Sanitize our 'account_key'. 145 | $settings['account_key'] = sanitize_text_field( $settings['account_key'] ); 146 | return $settings; 147 | } 148 | } 149 | --------------------------------------------------------------------------------