diff --git a/packages/e2e-tests/plugins/plugins-api.php b/packages/e2e-tests/plugins/plugins-api.php index a1c91596faea5..1accfb3fc718d 100644 --- a/packages/e2e-tests/plugins/plugins-api.php +++ b/packages/e2e-tests/plugins/plugins-api.php @@ -73,6 +73,19 @@ function enqueue_plugins_api_plugin_scripts() { filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/annotations-sidebar.js' ), true ); + + wp_enqueue_script( + 'gutenberg-test-plugins-api-document-setting', + plugins_url( 'plugins-api/document-setting.js', __FILE__ ), + array( + 'wp-edit-post', + 'wp-element', + 'wp-i18n', + 'wp-plugins', + ), + filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/document-setting.js' ), + true + ); } add_action( 'init', 'enqueue_plugins_api_plugin_scripts' ); diff --git a/packages/e2e-tests/plugins/plugins-api/document-setting.js b/packages/e2e-tests/plugins/plugins-api/document-setting.js new file mode 100644 index 0000000000000..b244800c25809 --- /dev/null +++ b/packages/e2e-tests/plugins/plugins-api/document-setting.js @@ -0,0 +1,21 @@ +( function() { + var el = wp.element.createElement; + var __ = wp.i18n.__; + var registerPlugin = wp.plugins.registerPlugin; + var PluginDocumentSettingPanel = wp.editPost.PluginDocumentSettingPanel; + + function MyDocumentSettingPlugin() { + return el( + PluginDocumentSettingPanel, + { + className: 'my-document-setting-plugin', + title: 'My Custom Panel' + }, + __( 'My Document Setting Panel' ) + ); + } + + registerPlugin( 'my-document-setting-plugin', { + render: MyDocumentSettingPlugin + } ); +} )(); diff --git a/packages/e2e-tests/specs/plugins/__snapshots__/plugins-api.test.js.snap b/packages/e2e-tests/specs/plugins/__snapshots__/plugins-api.test.js.snap index a3dda4545d67d..0d8533597b041 100644 --- a/packages/e2e-tests/specs/plugins/__snapshots__/plugins-api.test.js.snap +++ b/packages/e2e-tests/specs/plugins/__snapshots__/plugins-api.test.js.snap @@ -1,3 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Using Plugins API Document Setting Custom Panel Should render a custom panel inside Document Setting sidebar 1`] = ` +" +My Custom Panel +" +`; + exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `"
(no title)
Sidebar title plugin
"`; diff --git a/packages/e2e-tests/specs/plugins/plugins-api.test.js b/packages/e2e-tests/specs/plugins/plugins-api.test.js index d264bb736ed08..904fcaf0914e0 100644 --- a/packages/e2e-tests/specs/plugins/plugins-api.test.js +++ b/packages/e2e-tests/specs/plugins/plugins-api.test.js @@ -76,4 +76,12 @@ describe( 'Using Plugins API', () => { expect( pluginSidebarClosed ).toBeNull(); } ); } ); + + describe( 'Document Setting Custom Panel', () => { + it( 'Should render a custom panel inside Document Setting sidebar', async () => { + await openDocumentSettingsSidebar(); + const pluginDocumentSettingsText = await page.$eval( '.edit-post-sidebar .my-document-setting-plugin', ( el ) => el.innerText ); + expect( pluginDocumentSettingsText ).toMatchSnapshot(); + } ); + } ); } ); diff --git a/packages/edit-post/README.md b/packages/edit-post/README.md index 4c2c8e46b2cfb..6b895c79e75fb 100644 --- a/packages/edit-post/README.md +++ b/packages/edit-post/README.md @@ -100,6 +100,60 @@ _Returns_ - `WPElement`: The WPElement to be rendered. +# **PluginDocumentSettingPanel** + +Renders items below the Status & Availability panel in the Document Sidebar. + +_Usage_ + +```js +// Using ES5 syntax +var el = wp.element.createElement; +var __ = wp.i18n.__; +var registerPlugin = wp.plugins.registerPlugin; +var PluginDocumentSettingPanel = wp.editPost.PluginDocumentSettingPanel; + +function MyDocumentSettingPlugin() { + return el( + PluginDocumentSettingPanel, + { + className: 'my-document-setting-plugin', + }, + __( 'My Document Setting Panel' ) + ); +} + +registerPlugin( 'my-document-setting-plugin', { + render: MyDocumentSettingPlugin +} ); +``` + +```jsx +// Using ESNext syntax +const { registerPlugin } = wp.plugins; +const { PluginDocumentSettingPanel } = wp.editPost; + +const MyDocumentSettingTest = () => ( + +

My Document Setting Panel

+ +); + + registerPlugin( 'document-setting-test', { render: MyDocumentSettingTest } ); +``` + +_Parameters_ + +- _props_ `Object`: Component properties. +- _props.name_ `[string]`: The machine-friendly name for the panel. +- _props.className_ `[string]`: An optional class name added to the row. +- _props.title_ `[string]`: The title of the panel +- _props.icon_ `[(string|Element)]`: The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. + +_Returns_ + +- `WPElement`: The WPElement to be rendered. + # **PluginMoreMenuItem** Renders a menu item in `Plugins` group in `More Menu` drop down, and can be used to as a button or link depending on the props provided. diff --git a/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js b/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js new file mode 100644 index 0000000000000..a4ba4b924273b --- /dev/null +++ b/packages/edit-post/src/components/sidebar/plugin-document-setting-panel/index.js @@ -0,0 +1,106 @@ +/** + * Defines as extensibility slot for the Settings sidebar + */ + +/** + * WordPress dependencies + */ +import { createSlotFill, PanelBody } from '@wordpress/components'; +import { compose } from '@wordpress/compose'; +import { withPluginContext } from '@wordpress/plugins'; +import { withDispatch, withSelect } from '@wordpress/data'; + +export const { Fill, Slot } = createSlotFill( 'PluginDocumentSettingPanel' ); + +const PluginDocumentSettingFill = ( { isEnabled, opened, onToggle, className, title, icon, children } ) => { + if ( ! isEnabled ) { + return null; + } + return ( + + + { children } + + + ); +}; + +/** + * Renders items below the Status & Availability panel in the Document Sidebar. + * + * @param {Object} props Component properties. + * @param {string} [props.name] The machine-friendly name for the panel. + * @param {string} [props.className] An optional class name added to the row. + * @param {string} [props.title] The title of the panel + * @param {string|Element} [props.icon=inherits from the plugin] The [Dashicon](https://developer.wordpress.org/resource/dashicons/) icon slug string, or an SVG WP element, to be rendered when the sidebar is pinned to toolbar. + * + * @example ES5 + * ```js + * // Using ES5 syntax + * var el = wp.element.createElement; + * var __ = wp.i18n.__; + * var registerPlugin = wp.plugins.registerPlugin; + * var PluginDocumentSettingPanel = wp.editPost.PluginDocumentSettingPanel; + * + * function MyDocumentSettingPlugin() { + * return el( + * PluginDocumentSettingPanel, + * { + * className: 'my-document-setting-plugin', + * }, + * __( 'My Document Setting Panel' ) + * ); + * } + * + * registerPlugin( 'my-document-setting-plugin', { + * render: MyDocumentSettingPlugin + * } ); + * ``` + * + * @example ESNext + * ```jsx + * // Using ESNext syntax + * const { registerPlugin } = wp.plugins; + * const { PluginDocumentSettingPanel } = wp.editPost; + * + * const MyDocumentSettingTest = () => ( + * + *

My Document Setting Panel

+ * + * ); + * + * registerPlugin( 'document-setting-test', { render: MyDocumentSettingTest } ); + * ``` + * + * @return {WPElement} The WPElement to be rendered. + */ +const PluginDocumentSettingPanel = compose( + withPluginContext( ( context, ownProps ) => { + return { + icon: ownProps.icon || context.icon, + panelName: `${ context.name }/${ ownProps.name }`, + }; + } ), + withSelect( ( select, { panelName } ) => { + return ( + { + opened: select( 'core/edit-post' ).isEditorPanelOpened( panelName ), + isEnabled: select( 'core/edit-post' ).isEditorPanelEnabled( panelName ), + } + ); + } ), + withDispatch( ( dispatch, { panelName } ) => ( { + onToggle() { + return dispatch( 'core/edit-post' ).toggleEditorPanelOpened( panelName ); + }, + } ) ), +)( PluginDocumentSettingFill ); + +PluginDocumentSettingPanel.Slot = Slot; +export default PluginDocumentSettingPanel; diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js index 81e8a0ba87eb0..49bb45eec0ce3 100644 --- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js +++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js @@ -20,6 +20,7 @@ import PostLink from '../post-link'; import DiscussionPanel from '../discussion-panel'; import PageAttributes from '../page-attributes'; import MetaBoxes from '../../meta-boxes'; +import PluginDocumentSettingPanel from '../plugin-document-setting-panel'; const SettingsSidebar = ( { sidebarName } ) => ( ( { sidebarName === 'edit-post/document' && ( <> + diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index 66d8c753b46ad..8027695313a6f 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -88,6 +88,7 @@ export function initializeEditor( id, postType, postId, settings, initialEdits ) } export { default as PluginBlockSettingsMenuItem } from './components/block-settings-menu/plugin-block-settings-menu-item'; +export { default as PluginDocumentSettingPanel } from './components/sidebar/plugin-document-setting-panel'; export { default as PluginMoreMenuItem } from './components/header/plugin-more-menu-item'; export { default as PluginPostPublishPanel } from './components/sidebar/plugin-post-publish-panel'; export { default as PluginPostStatusInfo } from './components/sidebar/plugin-post-status-info';