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

Ensure contributors can create tags and manage categories #6761

Merged
merged 11 commits into from
May 17, 2018
14 changes: 14 additions & 0 deletions core-data/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ export function receiveEntityRecords( kind, name, records ) {
};
}

/**
* Returns an action object used in signalling that taxonomies have been received.
*
* @param {Array} taxonomies Taxonomies received.
*
* @return {Object} Action object.
*/
export function receiveTaxonomies( taxonomies ) {
return {
type: 'RECEIVE_TAXONOMIES',
taxonomies,
};
}

/**
* Returns an action object used in signalling that the index has been received.
*
Expand Down
18 changes: 18 additions & 0 deletions core-data/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,23 @@ export function users( state = { byId: {}, queries: {} }, action ) {
return state;
}

/**
* Reducer managing taxonomies.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function taxonomies( state = [], action ) {
switch ( action.type ) {
case 'RECEIVE_TAXONOMIES':
return action.taxonomies;
}

return state;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding a new reducer/selectors/actions, we could just leverage the new entities abstraction to automatically generate those. https://github.com/WordPress/gutenberg/blob/master/core-data/entities.js#L6

Currently, the entities only support fetching by id getEntityRecord but we should definitely introduce a findAll/findQuery as well getEntityRecords( state, kind, entity, query )

If you think it's too much work, it's fine to do it separately.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd like to handle separately (and also include more tests within core-data). I've filed an issue #6780


/**
* Reducer managing theme supports data.
*
Expand Down Expand Up @@ -146,6 +163,7 @@ export const entities = combineReducers( Object.entries( entitiesByKind ).reduce
export default combineReducers( {
terms,
users,
taxonomies,
themeSupports,
entities,
} );
10 changes: 10 additions & 0 deletions core-data/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
receiveTerms,
receiveUserQuery,
receiveEntityRecords,
receiveTaxonomies,
receiveThemeSupportsFromIndex,
} from './actions';
import { getEntity } from './entities';
Expand Down Expand Up @@ -47,6 +48,15 @@ export async function* getEntityRecord( state, kind, name, key ) {
yield receiveEntityRecords( kind, name, record );
}

/**
* Requests taxonomies from the REST API, yielding action objects on request
* progress.
*/
export async function* getTaxonomies() {
const taxonomies = await apiRequest( { path: '/wp/v2/taxonomies?context=edit' } );
yield receiveTaxonomies( taxonomies );
}

/**
* Requests theme supports data from the index.
*/
Expand Down
11 changes: 11 additions & 0 deletions core-data/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ export function getEntityRecord( state, kind, name, key ) {
return state.entities[ kind ][ name ].byKey[ key ];
}

/**
* Returns all the available taxonomies.
*
* @param {Object} state Data state.
*
* @return {Array} Taxonomies list.
*/
export function getTaxonomies( state ) {
return state.taxonomies;
}

/**
* Return theme suports data in the index.
*
Expand Down
7 changes: 2 additions & 5 deletions editor/components/post-taxonomies/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import { some, includes } from 'lodash';
/**
* WordPress dependencies
*/
import { withAPIData } from '@wordpress/components';
import { compose } from '@wordpress/element';
import { withSelect } from '@wordpress/data';

export function PostTaxonomiesCheck( { postType, taxonomies, children } ) {
const hasTaxonomies = some( taxonomies.data, ( taxonomy ) => includes( taxonomy.types, postType ) );
const hasTaxonomies = some( taxonomies, ( taxonomy ) => includes( taxonomy.types, postType ) );
if ( ! hasTaxonomies ) {
return null;
}
Expand All @@ -23,10 +22,8 @@ export default compose( [
withSelect( ( select ) => {
return {
postType: select( 'core/editor' ).getCurrentPostType(),
taxonomies: select( 'core' ).getTaxonomies(),
};
} ),
withAPIData( () => ( {
taxonomies: '/wp/v2/taxonomies?context=edit',
} ) ),
] )( PostTaxonomiesCheck );

10 changes: 9 additions & 1 deletion editor/components/post-taxonomies/flat-term-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,12 @@ class FlatTermSelector extends Component {
}

render() {
const { slug, taxonomy } = this.props;
const { slug, taxonomy, hasAssignAction } = this.props;

if ( ! hasAssignAction ) {
return null;
}

const { loading, availableTerms, selectedTerms } = this.state;
const termNames = availableTerms.map( ( term ) => term.name );
const newTermPlaceholderLabel = get(
Expand Down Expand Up @@ -202,7 +207,10 @@ export default compose(
};
} ),
withSelect( ( select, ownProps ) => {
const { getCurrentPost } = select( 'core/editor' );
return {
hasCreateAction: get( getCurrentPost(), [ '_links', 'wp:action-create-' + ownProps.restBase ], false ),
Copy link
Member

Choose a reason for hiding this comment

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

Should this logic be its own selector? Something like canUserForPost( actionType, restBase ) ?

Minor: getCurrentPost as implemented is trivial, though nothing guarantees it is, in which case assigning a single variable of const currentPost = getCurrentPost() to use across the two merged props would be marginally more performant.

Copy link
Member Author

Choose a reason for hiding this comment

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

Should this logic be its own selector? Something like canUserForPost( actionType, restBase ) ?

See #6655

hasAssignAction: get( getCurrentPost(), [ '_links', 'wp:action-assign-' + ownProps.restBase ], false ),
terms: select( 'core/editor' ).getEditedPostAttribute( ownProps.restBase ),
};
} ),
Expand Down
12 changes: 10 additions & 2 deletions editor/components/post-taxonomies/hierarchical-term-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,12 @@ class HierarchicalTermSelector extends Component {
}

render() {
const { slug, taxonomy, instanceId } = this.props;
const { slug, taxonomy, instanceId, hasCreateAction, hasAssignAction } = this.props;

if ( ! hasAssignAction ) {
return null;
}

const { availableTermsTree, availableTerms, formName, formParent, loading, showForm } = this.state;
const labelWithFallback = ( labelProperty, fallbackIsCategory, fallbackIsNotCategory ) => get(
taxonomy,
Expand Down Expand Up @@ -245,7 +250,7 @@ class HierarchicalTermSelector extends Component {
/* eslint-disable jsx-a11y/no-onchange */
return [
...this.renderTerms( availableTermsTree ),
! loading && (
! loading && hasCreateAction && (
<button
key="term-add-button"
onClick={ this.onToggleForm }
Expand Down Expand Up @@ -301,7 +306,10 @@ export default compose( [
};
} ),
withSelect( ( select, ownProps ) => {
const { getCurrentPost } = select( 'core/editor' );
return {
hasCreateAction: get( getCurrentPost(), [ '_links', 'wp:action-create-' + ownProps.restBase ], false ),
hasAssignAction: get( getCurrentPost(), [ '_links', 'wp:action-assign-' + ownProps.restBase ], false ),
terms: select( 'core/editor' ).getEditedPostAttribute( ownProps.restBase ),
};
} ),
Expand Down
7 changes: 2 additions & 5 deletions editor/components/post-taxonomies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { filter, identity, includes } from 'lodash';
/**
* WordPress dependencies
*/
import { withAPIData } from '@wordpress/components';
import { compose, Fragment } from '@wordpress/element';
import { withSelect } from '@wordpress/data';

Expand All @@ -18,7 +17,7 @@ import HierarchicalTermSelector from './hierarchical-term-selector';
import FlatTermSelector from './flat-term-selector';

export function PostTaxonomies( { postType, taxonomies, taxonomyWrapper = identity } ) {
const availableTaxonomies = filter( taxonomies.data, ( taxonomy ) => includes( taxonomy.types, postType ) );
const availableTaxonomies = filter( taxonomies, ( taxonomy ) => includes( taxonomy.types, postType ) );
const visibleTaxonomies = filter( availableTaxonomies, ( taxonomy ) => taxonomy.visibility.show_ui );
return visibleTaxonomies.map( ( taxonomy ) => {
const TaxonomyComponent = taxonomy.hierarchical ? HierarchicalTermSelector : FlatTermSelector;
Expand All @@ -42,10 +41,8 @@ export default compose( [
withSelect( ( select ) => {
return {
postType: select( 'core/editor' ).getCurrentPostType(),
taxonomies: select( 'core' ).getTaxonomies(),
};
} ),
withAPIData( () => ( {
taxonomies: '/wp/v2/taxonomies?context=edit',
} ) ),
] )( PostTaxonomies );

38 changes: 15 additions & 23 deletions editor/components/post-taxonomies/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,21 @@ describe( 'PostTaxonomies', () => {

const wrapperOne = shallow(
<PostTaxonomies postType="book"
taxonomies={ {
data: [ genresTaxonomy, categoriesTaxonomy ],
} }
taxonomies={ [ genresTaxonomy, categoriesTaxonomy ] }
/>
);

expect( wrapperOne.at( 0 ) ).toHaveLength( 1 );

const wrapperTwo = shallow(
<PostTaxonomies postType="book"
taxonomies={ {
data: [
genresTaxonomy,
{
...categoriesTaxonomy,
types: [ 'post', 'page', 'book' ],
},
],
} }
taxonomies={ [
genresTaxonomy,
{
...categoriesTaxonomy,
types: [ 'post', 'page', 'book' ],
},
] }
/>
);

Expand All @@ -83,24 +79,20 @@ describe( 'PostTaxonomies', () => {

const wrapperOne = shallow(
<PostTaxonomies postType="book"
taxonomies={ {
data: [ genresTaxonomy ],
} }
taxonomies={ [ genresTaxonomy ] }
/>
);

expect( wrapperOne.at( 0 ) ).toHaveLength( 1 );

const wrapperTwo = shallow(
<PostTaxonomies postType="book"
taxonomies={ {
data: [
{
...genresTaxonomy,
visibility: { show_ui: false },
},
],
} }
taxonomies={ [
{
...genresTaxonomy,
visibility: { show_ui: false },
},
] }
/>
);

Expand Down
Loading