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

Blocks: Add a way to manage block categories #7606

Merged
merged 3 commits into from Jun 28, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 11 additions & 2 deletions blocks/api/categories.js
@@ -1,13 +1,22 @@
/**
* WordPress dependencies
*/
import { select } from '@wordpress/data';
import { dispatch, select } from '@wordpress/data';

/**
* Returns all the block categories.
*
* @return {Array} Block categories.
* @return {Object[]} Block categories.
*/
export function getCategories() {
return select( 'core/blocks' ).getCategories();
}

/**
* Sets the block categories.
*
* @param {Object[]} categories Block categories.
*/
export function setCategories( categories ) {
dispatch( 'core/blocks' ).setCategories( categories );
}
5 changes: 4 additions & 1 deletion blocks/api/index.js
Expand Up @@ -20,7 +20,10 @@ export {
getSaveElement,
} from './serializer';
export { isValidBlock } from './validation';
export { getCategories } from './categories';
export {
getCategories,
setCategories,
} from './categories';
export {
registerBlockType,
unregisterBlockType,
Expand Down
14 changes: 14 additions & 0 deletions blocks/store/actions.js
Expand Up @@ -58,3 +58,17 @@ export function setFallbackBlockName( name ) {
name,
};
}

/**
* Returns an action object used to set block categories.
*
* @param {Object[]} categories Block categories.
*
* @return {Object} Action object.
*/
export function setCategories( categories ) {
return {
type: 'SET_CATEGORIES',
categories,
};
}
6 changes: 2 additions & 4 deletions blocks/store/reducer.js
Expand Up @@ -80,10 +80,8 @@ export const fallbackBlockName = createBlockNameSetterReducer( 'SET_FALLBACK_BLO
* @return {Object} Updated state.
*/
export function categories( state = DEFAULT_CATEGORIES, action ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we want to keep the DEFAULT_CATEGORIES in the client?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That question will come up with the blocks as well. I think we need a way to generate scripts bundled as separate modules in case someone wants to use Gutenberg fully client-side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it seems fine to have a default set in the client. From purely a maintainability perspective, it would be nice if we could avoid maintaining two separate sets of the same values though (e.g. somehow inject into the client JS from the server default value, or vice-versa).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought about that, too. It would be nice to have it in one place, but it is tricky because of translations. I opted for duplication to move on. I open a follow-up issue where we can discuss how to tackle the standalone case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already some previous work done by @aduth bin/get-server-blocks.php that can achieve something close to what we need.

if ( action.type === 'ADD_CATEGORIES' ) {
const addedSlugs = map( action.categories, ( category ) => category.slug );
const previousState = filter( state, ( category ) => addedSlugs.indexOf( category.slug ) === -1 );
return [ ...previousState, ...action.categories ];
if ( action.type === 'SET_CATEGORIES' ) {
return action.categories || [];
}

return state;
Expand Down
5 changes: 2 additions & 3 deletions blocks/store/test/reducer.js
Expand Up @@ -99,18 +99,17 @@ describe( 'categories', () => {
expect( categories( undefined, {} ) ).toEqual( DEFAULT_CATEGORIES );
} );

it( 'should add add a new category', () => {
it( 'should override categories', () => {
const original = deepFreeze( [
{ slug: 'chicken', title: 'Chicken' },
] );

const state = categories( original, {
type: 'ADD_CATEGORIES',
type: 'SET_CATEGORIES',
categories: [ { slug: 'wings', title: 'Wings' } ],
} );

expect( state ).toEqual( [
{ slug: 'chicken', title: 'Chicken' },
{ slug: 'wings', title: 'Wings' },
] );
} );
Expand Down
25 changes: 23 additions & 2 deletions docs/extensibility/extending-blocks.md
Expand Up @@ -189,9 +189,30 @@ On the server, you can filter the list of blocks shown in the inserter using the

```php
add_filter( 'allowed_block_types', function( $allowed_block_types, $post ) {
if ( $post->post_type === 'post' ) {
if ( $post->post_type !== 'post' ) {
return $allowed_block_types;
}
return [ 'core/paragraph' ];
return array( 'core/paragraph' );
}, 10, 2 );
```

## Managing block categories

It is possible to filter the list of default block categories using the `block_categories` filter. You can do it on the server by implementing a function which returns a list of categories. It is going to be used during blocks registration and to group blocks in the inserter. You can also use the second provided param `$post` to generate a different list depending on the post's content.

```php
add_filter( 'block_categories', function( $categories, $post ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this example is not PHP 5.2.x compliant (with use of closure, vs. named function).

Copy link
Member Author

@gziolo gziolo Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, phpcs complained when I pasted it into codebase. I will split it into 5.2.x style before merging.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e75c4f3.

if ( $post->post_type !== 'post' ) {
return $categories;
}
return array_merge(
$categories,
array(
array(
'slug' => 'my-category',
'title' => __( 'My category', 'my-plugin' ),
),
)
);
}, 10, 2 );
```
45 changes: 45 additions & 0 deletions lib/client-assets.php
Expand Up @@ -982,6 +982,45 @@ function get_autosave_newer_than_post_save( $post ) {
return false;
}

/**
* Returns all the block categories.
*
* @since 2.2.0
*
* @param WP_Post $post Post object.
* @return Object[] Block categories.
*/
function get_block_categories( $post ) {
$default_categories = array(
array(
'slug' => 'common',
'title' => __( 'Common Blocks', 'gutenberg' ),
),
array(
'slug' => 'formatting',
'title' => __( 'Formatting', 'gutenberg' ),
),
array(
'slug' => 'layout',
'title' => __( 'Layout Elements', 'gutenberg' ),
),
array(
'slug' => 'widgets',
'title' => __( 'Widgets', 'gutenberg' ),
),
array(
'slug' => 'embed',
'title' => __( 'Embeds', 'gutenberg' ),
),
array(
'slug' => 'shared',
'title' => __( 'Shared Blocks', 'gutenberg' ),
),
);

return apply_filters( 'block_categories', $default_categories, $post );
}

/**
* Scripts & Styles.
*
Expand Down Expand Up @@ -1043,6 +1082,12 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
'after'
);

wp_add_inline_script(
'wp-blocks',
sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ) ) ),
'after'
);

// Prepopulate with some test content in demo.
if ( $is_new_post && $is_demo ) {
wp_add_inline_script(
Expand Down