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

Adds How to Extend the Editor guide to handbook #69091

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
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
296 changes: 296 additions & 0 deletions docs/how-to-guides/extend-editor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
# How to Extend the WordPress Editor

This guide explains the various ways you can extend and customize the WordPress Block Editor (Gutenberg) to create rich editing experiences. You'll learn about the core extension mechanisms, see practical examples, and discover best practices for building editor extensions.

## Introduction

The WordPress Block Editor is designed to be highly extensible. There are several primary ways to extend the editor:

1. **SlotFills**: Components that allow you to inject content into predefined areas of the editor
2. **Editor Filters**: JavaScript filters that modify editor behavior
3. **Block Variations**: Predefined configurations of existing blocks
4. **Custom Blocks**: Entirely new block types

## SlotFill System

The SlotFill system is a core concept in editor extensibility. It provides specific locations ("Slots") throughout the editor interface where you can inject your custom components ("Fills").

### Common SlotFill Locations

#### 1. PluginSidebar

The `PluginSidebar` allows you to add a new panel to the editor's sidebar.

```jsx
import { PluginSidebar } from '@wordpress/edit-post';
import { TextControl } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';

function CustomSidebar() {
const metaValue = useSelect(select =>
select('core/editor').getEditedPostAttribute('meta')['custom_meta_key']
);

const { editPost } = useDispatch('core/editor');

return (
<PluginSidebar
name="custom-sidebar"
title="Custom Fields"
icon="admin-post"
>
<TextControl
label="Custom Field"
value={metaValue}
onChange={(value) => {
editPost({
meta: { custom_meta_key: value }
});
}}
/>
</PluginSidebar>
);
}
```

#### 2. PluginDocumentSettingPanel

Add custom panels to the Document sidebar:

```jsx
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';

function CustomDocumentPanel() {
return (
<PluginDocumentSettingPanel
name="custom-panel"
title="Custom Settings"
>
{/* Your custom settings UI */}
</PluginDocumentSettingPanel>
);
}
```

#### 3. PluginBlockSettingsMenuItem

Add items to the block settings menu (three dots menu):

```jsx
import { PluginBlockSettingsMenuItem } from '@wordpress/edit-post';

function CustomBlockMenuItem() {
return (
<PluginBlockSettingsMenuItem
allowedBlocks={['core/paragraph']}
icon="admin-tools"
label="Custom Action"
onClick={() => {
// Handle click
}}
/>
);
}
```

#### 4. PluginPrePublishPanel

Add custom panels to the pre-publish sidebar:

```jsx
import { PluginPrePublishPanel } from '@wordpress/edit-post';

function CustomPrePublishPanel() {
return (
<PluginPrePublishPanel
name="custom-panel"
title="Pre-publish Checks"
>
{/* Pre-publish check UI */}
</PluginPrePublishPanel>
);
}
```

## Editor Filters

Editor filters allow you to modify editor behavior without creating new UI components.

### Common Filter Examples

#### 1. Modify Block Settings

```jsx
import { addFilter } from '@wordpress/hooks';

function addCustomAttribute(settings, name) {
if (name !== 'core/paragraph') {
return settings;
}

return {
...settings,
attributes: {
...settings.attributes,
customAttribute: {
type: 'string',
default: '',
},
},
};
}

addFilter(
'blocks.registerBlockType',
'my-plugin/custom-attribute',
addCustomAttribute
);
```

#### 2. Filter Block Content

```jsx
import { addFilter } from '@wordpress/hooks';

function addCustomContent(BlockEdit) {
return (props) => {
if (props.name !== 'core/paragraph') {
return <BlockEdit {...props} />;
}

return (
<div className="custom-wrapper">
<BlockEdit {...props} />
{/* Additional content */}
</div>
);
};
}

addFilter(
'editor.BlockEdit',
'my-plugin/custom-content',
addCustomContent
);
```

## Best Practices

### 1. Use Core Components

Always use WordPress core components to maintain consistency:

```jsx
// Good
import { Button, TextControl, SelectControl } from '@wordpress/components';

// Avoid custom HTML elements
```

### 2. Follow WordPress Design Patterns

- Use the WordPress color palette
- Maintain consistent spacing
- Follow existing UI patterns
- Use standard icons from `@wordpress/icons`

### 3. Performance Considerations

- Use memoization for expensive computations
- Implement proper cleanup in useEffect hooks
- Avoid unnecessary re-renders

```jsx
import { memo, useCallback } from '@wordpress/element';

const CustomComponent = memo(function CustomComponent({ value, onChange }) {
const handleChange = useCallback((newValue) => {
onChange(newValue);
}, [onChange]);

return (
// Component implementation
);
});
```

### 4. Accessibility

- Ensure keyboard navigation works
- Use ARIA attributes appropriately
- Maintain proper heading hierarchy
- Provide sufficient color contrast

### 5. Data Management

Use the WordPress data system:

```jsx
import { useSelect, useDispatch } from '@wordpress/data';

function CustomComponent() {
const { posts } = useSelect(select => ({
posts: select('core').getEntityRecords('postType', 'post')
}));

const { editPost } = useDispatch('core/editor');

// Component implementation
}
```

## Common Extension Patterns

### 1. Register a Plugin

```jsx
import { registerPlugin } from '@wordpress/plugins';

registerPlugin('my-custom-plugin', {
icon: 'admin-customizer',
render: () => (
<>
<CustomSidebar />
<CustomDocumentPanel />
</>
),
});
```

### 2. Add Custom Meta Boxes

```jsx
function registerMetaField() {
register_post_meta('post', 'custom_meta_key', {
type: 'string',
single: true,
show_in_rest: true,
});
}
add_action('init', 'registerMetaField');
```

### 3. Block Variations

```jsx
import { registerBlockVariation } from '@wordpress/blocks';

registerBlockVariation('core/group', {
name: 'custom-group',
title: 'Custom Group',
attributes: {
className: 'custom-group',
},
innerBlocks: [
['core/paragraph', {}],
['core/image', {}],
],
});
```

## Related Resources

- [Block Editor Handbook](https://developer.wordpress.org/block-editor/)
- [SlotFill Reference](https://developer.wordpress.org/block-editor/reference-guides/slotfills/)
- [Components Reference](https://developer.wordpress.org/block-editor/reference-guides/components/)
- [Data Module Reference](https://developer.wordpress.org/block-editor/reference-guides/data/)
Loading