Skip to content

Commit

Permalink
Rename reusable blocks to patterns & allow user created patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
glendaviesnz authored and aaronrobertshaw committed Jun 16, 2023
1 parent c062fc5 commit e5b1ab7
Show file tree
Hide file tree
Showing 20 changed files with 271 additions and 35 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Add a user’s avatar. ([Source](https://github.com/WordPress/gutenberg/tree/tru
- **Supports:** align, color (~~background~~, ~~text~~), spacing (margin, padding), ~~alignWide~~, ~~html~~
- **Attributes:** isLink, linkTarget, size, userId

## Reusable block
## Pattern

Create and save content to reuse across your site. Update the block, and the changes apply everywhere it’s used. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/block))

Expand Down
91 changes: 91 additions & 0 deletions lib/compat/wordpress-6.3/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,94 @@ function gutenberg_add_selectors_property_to_block_type_settings( $settings, $me
return $settings;
}
add_filter( 'block_type_metadata_settings', 'gutenberg_add_selectors_property_to_block_type_settings', 10, 2 );

/**
* Adds custom fields support to the wp_block post type so an unsynced option can be added and renames
* from Reusable block to Pattern.
*
* Note: This should be removed when the minimum required WP version is >= 6.3.
*
* @see https://github.com/WordPress/gutenberg/pull/51144
*
* @param array $args Register post type args.
* @param string $post_type The post type string.
*
* @return array Register post type args.
*/
function gutenberg_add_custom_fields_to_wp_block( $args, $post_type ) {
if ( 'wp_block' === $post_type ) {
$args['labels']['name'] = _x( 'Patterns', 'post type general name' );
$args['labels']['singular_name'] = _x( 'Pattern', 'post type singular name' );
$args['labels']['add_new_item'] = __( 'Add new Pattern' );
$args['labels']['new_item'] = __( 'New Pattern' );
$args['labels']['edit_item'] = __( 'Edit Pattern' );
$args['labels']['view_item'] = __( 'View Pattern' );
$args['labels']['all_items'] = __( 'All Patterns' );
$args['labels']['search_items'] = __( 'Search Patterns' );
$args['labels']['not_found'] = __( 'No Patterns found.' );
$args['labels']['not_found_in_trash'] = __( 'No Patterns found in Trash.' );
$args['labels']['filter_items_list'] = __( 'Filter Patterns list' );
$args['labels']['items_list_navigation'] = __( 'Patterns list navigation' );
$args['labels']['items_list'] = __( 'Patterns list' );
$args['labels']['item_published'] = __( 'Pattern published.' );
$args['labels']['item_published_privately'] = __( 'Pattern published privately.' );
$args['labels']['item_reverted_to_draft'] = __( 'Pattern reverted to draft.' );
$args['labels']['item_scheduled'] = __( 'Pattern scheduled.' );
$args['labels']['item_updated'] = __( 'Pattern updated.' );
array_push( $args['supports'], 'custom-fields' );
}

return $args;
}
add_filter( 'register_post_type_args', 'gutenberg_add_custom_fields_to_wp_block', 10, 2 );

/**
* Adds wp_block_sync_status meta fields to the wp_block post type so an unsynced option can be added.
*
* Note: This should be removed when the minimum required WP version is >= 6.3.
*
* @see https://github.com/WordPress/gutenberg/pull/51144
*
* @return void
*/
function gutenberg_wp_block_register_post_meta() {
$post_type = 'wp_block';
register_post_meta(
$post_type,
'wp_block',
array(
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
},
'sanitize_callback' => 'gutenberg_wp_block_sanitize_post_meta',
'single' => true,
'type' => 'object',
'show_in_rest' => array(
'schema' => array(
'type' => 'object',
'properties' => array(
'sync_status' => array(
'type' => 'string',
),
),
),
),
)
);
}
/**
* Sanitizes the array of wp_block post meta categories array.
*
* Note: This should be removed when the minimum required WP version is >= 6.3.
*
* @see https://github.com/WordPress/gutenberg/pull/51144
*
* @param array $meta_value Array of values to sanitize.
*
* @return array Sanitized array of values.
*/
function gutenberg_wp_block_sanitize_post_meta( $meta_value ) {
$meta_value['sync_status'] = sanitize_text_field( $meta_value['sync_status'] );
return $meta_value;
}
add_action( 'init', 'gutenberg_wp_block_register_post_meta' );
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ function ReusableBlocksList( { onHover, onInsert, rootClientId } ) {
}

return (
<InserterPanel title={ __( 'Reusable blocks' ) }>
<InserterPanel title={ __( 'Synced Patterns' ) }>
<BlockTypesList
items={ filteredItems }
onSelect={ onSelectItem }
onHover={ onHover }
label={ __( 'Reusable blocks' ) }
label={ __( 'Synced Patterns' ) }
/>
</InserterPanel>
);
Expand Down Expand Up @@ -67,7 +67,7 @@ export function ReusableBlocksTab( { rootClientId, onInsert, onHover } ) {
post_type: 'wp_block',
} ) }
>
{ __( 'Manage Reusable blocks' ) }
{ __( 'Manage Synced Patterns' ) }
</Button>
</div>
</>
Expand Down
6 changes: 3 additions & 3 deletions packages/block-editor/src/components/inserter/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ const blocksTab = {
};
const patternsTab = {
name: 'patterns',
/* translators: Patterns tab title in the block inserter. */
/* translators: Theme and Directory Patterns tab title in the block inserter. */
title: __( 'Patterns' ),
};
const reusableBlocksTab = {
name: 'reusable',
/* translators: Reusable blocks tab title in the block inserter. */
title: __( 'Reusable' ),
/* translators: Locally created Patterns tab title in the block inserter. */
title: __( 'Synced Patterns' ),
icon: reusableBlockIcon,
};
const mediaTab = {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/block/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "core/block",
"title": "Reusable block",
"title": "Pattern",
"category": "reusable",
"description": "Create and save content to reuse across your site. Update the block, and the changes apply everywhere it’s used.",
"textdomain": "default",
Expand Down
15 changes: 15 additions & 0 deletions packages/block-library/src/block/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from '@wordpress/block-editor';
import { store as reusableBlocksStore } from '@wordpress/reusable-blocks';
import { ungroup } from '@wordpress/icons';
import { cloneBlock } from '@wordpress/blocks';

export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) {
const hasAlreadyRendered = useHasRecursion( ref );
Expand All @@ -54,11 +55,25 @@ export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) {
const { __experimentalConvertBlockToStatic: convertBlockToStatic } =
useDispatch( reusableBlocksStore );

const { replaceBlocks } = useDispatch( blockEditorStore );

const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
'wp_block',
{ id: ref }
);

if (
hasResolved &&
record?.meta?.wp_block?.sync_status === 'unsynced' &&
blocks.length > 0
) {
replaceBlocks(
clientId,
blocks.map( ( block ) => cloneBlock( block ) )
);
}

const [ title, setTitle ] = useEntityProp(
'postType',
'wp_block',
Expand Down
6 changes: 3 additions & 3 deletions packages/block-library/src/block/test/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe( 'Reusable block', () => {

// Get the reusable block.
const [ reusableBlock ] = await screen.findAllByLabelText(
/Reusable block Block\. Row 1/
/Pattern Block\. Row 1/
);

expect( reusableBlock ).toBeDefined();
Expand All @@ -131,7 +131,7 @@ describe( 'Reusable block', () => {
} );

const [ reusableBlock ] = await screen.findAllByLabelText(
/Reusable block Block\. Row 1/
/Pattern Block\. Row 1/
);

const blockDeleted = within( reusableBlock ).getByText(
Expand Down Expand Up @@ -164,7 +164,7 @@ describe( 'Reusable block', () => {
} );

const [ reusableBlock ] = await screen.findByLabelText(
/Reusable block Block\. Row 1/
/Pattern Block\. Row 1/
);

const innerBlockListWrapper = await within(
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/block/test/transforms.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getBlockTransformOptions,
} from 'test/helpers';

const block = 'Reusable block';
const block = 'Pattern';
const initialHtml = `
<!-- wp:block {"ref":130} /-->`;

Expand Down
7 changes: 6 additions & 1 deletion packages/e2e-test-utils/src/create-reusable-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,22 @@ import { canvas } from './canvas';
export const createReusableBlock = async ( content, title ) => {
const reusableBlockNameInputSelector =
'.reusable-blocks-menu-items__convert-modal .components-text-control__input';
const syncToggleSelector = '.components-form-toggle__input';
// Insert a paragraph block
await insertBlock( 'Paragraph' );
await page.keyboard.type( content );

await clickBlockToolbarButton( 'Options' );
await clickMenuItem( 'Create Reusable block' );
await clickMenuItem( 'Create a Pattern' );
const nameInput = await page.waitForSelector(
reusableBlockNameInputSelector
);
await nameInput.click();
await page.keyboard.type( title );
const syncToggle = await page.waitForSelector(
`${ reusableBlockNameInputSelector } ${ syncToggleSelector }`
);
syncToggle.click();
await page.keyboard.press( 'Enter' );

// Wait for creation to finish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe( 'block editor keyboard shortcuts', () => {
} );
it( 'should prevent deleting multiple selected blocks from inputs', async () => {
await clickBlockToolbarButton( 'Options' );
await clickMenuItem( 'Create Reusable block' );
await clickMenuItem( 'Create a Pattern' );
const reusableBlockNameInputSelector =
'.reusable-blocks-menu-items__convert-modal .components-text-control__input';
const nameInput = await page.waitForSelector(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@wordpress/components';
import { withSelect, withDispatch } from '@wordpress/data';
import { compose, ifCondition } from '@wordpress/compose';
import { PostSwitchToDraftButton } from '@wordpress/editor';
import { PostSwitchToDraftButton, PostSyncStatus } from '@wordpress/editor';

/**
* Internal dependencies
Expand Down Expand Up @@ -51,6 +51,7 @@ function PostStatus( { isOpened, onTogglePanel } ) {
<PostFormat />
<PostSlug />
<PostAuthor />
<PostSyncStatus />
{ fills }
<HStack
style={ {
Expand Down
2 changes: 1 addition & 1 deletion packages/edit-post/src/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ registerPlugin( 'edit-post', {
post_type: 'wp_block',
} ) }
>
{ __( 'Manage Reusable blocks' ) }
{ __( 'Manage Patterns' ) }
</MenuItem>
<KeyboardShortcutsHelpMenuItem
onSelect={ onClose }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const config = {
loading: __( 'Loading library' ),
notFound: __( 'No patterns found' ),
manage: __( 'Manage all template parts' ),
reusableBlocks: __( 'Manage reusable blocks' ),
reusableBlocks: __( 'Manage patterns' ),
description: __(
'Template Parts are small pieces of a layout that can be reused across multiple templates and always appear the same way. Common template parts include the site header, footer, or sidebar.'
),
Expand Down
1 change: 1 addition & 0 deletions packages/editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export { default as PostSlugCheck } from './post-slug/check';
export { default as PostSticky } from './post-sticky';
export { default as PostStickyCheck } from './post-sticky/check';
export { default as PostSwitchToDraftButton } from './post-switch-to-draft-button';
export { default as PostSyncStatus } from './post-sync-status';
export { default as PostTaxonomies } from './post-taxonomies';
export { FlatTermSelector as PostTaxonomiesFlatTermSelector } from './post-taxonomies/flat-term-selector';
export { HierarchicalTermSelector as PostTaxonomiesHierarchicalTermSelector } from './post-taxonomies/hierarchical-term-selector';
Expand Down
55 changes: 55 additions & 0 deletions packages/editor/src/components/post-sync-status/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* WordPress dependencies
*/
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { ToggleControl, PanelRow } from '@wordpress/components';

/**
* Internal dependencies
*/
import { store as editorStore } from '../../store';

export default function PostSyncStatus() {
const { editPost } = useDispatch( editorStore );
const { meta, postType } = useSelect( ( select ) => {
const { getEditedPostAttribute } = select( editorStore );
return {
meta: getEditedPostAttribute( 'meta' ),
postType: getEditedPostAttribute( 'type' ),
};
}, [] );
if ( postType !== 'wp_block' ) {
return null;
}
const onUpdateSync = ( syncStatus ) =>
editPost( {
meta: {
...meta,
wp_block:
syncStatus === 'unsynced'
? { sync_status: syncStatus }
: null,
},
} );
const syncStatus = meta?.wp_block?.sync_status;
const isFullySynced = ! syncStatus;

return (
<PanelRow className="edit-post-sync-status">
<span>{ __( 'Syncing' ) }</span>
<ToggleControl
__nextHasNoMarginBottom
label={
isFullySynced ? __( 'Fully synced' ) : __( 'Not synced' )
}
checked={ isFullySynced }
onChange={ () => {
onUpdateSync(
syncStatus === 'unsynced' ? 'fully' : 'unsynced'
);
} }
/>
</PanelRow>
);
}
16 changes: 16 additions & 0 deletions packages/editor/src/components/post-sync-status/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.edit-post-sync-status {
width: 100%;
position: relative;
justify-content: flex-start;

> span {
display: block;
width: 45%;
flex-shrink: 0;
}

.components-base-control {
// Match padding on tertiary buttons for alignment.
padding-left: $grid-unit-15 * 0.5;
}
}
1 change: 1 addition & 0 deletions packages/editor/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@import "./components/post-publish-button/style.scss";
@import "./components/post-publish-panel/style.scss";
@import "./components/post-saved-state/style.scss";
@import "./components/post-sync-status/style.scss";
@import "./components/post-taxonomies/style.scss";
@import "./components/post-text-editor/style.scss";
@import "./components/post-url/style.scss";
Expand Down
Loading

0 comments on commit e5b1ab7

Please sign in to comment.