Skip to content

Commit

Permalink
Alternative: restrict Navigation permissions and show UI warning if c…
Browse files Browse the repository at this point in the history
…annot create (#37454)

* Test for publish abtility and display warning

* Update creation of Nav posts to require admin perms

* Only show menu creation option if user has permission to create

* Move permission selectors to hook

* Show warning if unable to create Navigation Menus

* Copy changes from Core patch

See https://github.com/WordPress/wordpress-develop/pull/2056/files

* Only show error if create is not allowed

* Revert "Copy changes from Core patch"

This reverts commit 1872f62a454dc41ce787103e3d1830f7ff00d63c.

* Use streamlined permissions

Kudos to @spacedmonkey for #37454 (comment)

* Remove inline warning and reenable ability to select existing

* Refactor Notices to reusable hook

* Add notices for creating Menus

* Rename dep for clarity

* Hide other creation options

* Add e2e test

* Hide classic Menus from dropdown

See #37454 (comment)

* Fix up e2e tests following changes from rebase

* Update to make component props more agnostic

* Make component props less tighly coupled to permissions

* Remove unneeded undefined fallback

* Refactor hooks

* Try switch user to admin

* Try switching back to admin after each permissions test

* Try targetting test that relies on avoiding a 404 from URL details endpoint
  • Loading branch information
getdave committed Dec 20, 2021
1 parent 037fcc7 commit 33ec385
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 83 deletions.
12 changes: 12 additions & 0 deletions lib/navigation.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ function gutenberg_register_navigation_post_type() {
'editor',
'revisions',
),
'capabilities' => array(
'edit_others_posts' => 'edit_theme_options',
'delete_posts' => 'edit_theme_options',
'publish_posts' => 'edit_theme_options',
'create_posts' => 'edit_theme_options',
'read_private_posts' => 'edit_theme_options',
'delete_private_posts' => 'edit_theme_options',
'delete_published_posts' => 'edit_theme_options',
'delete_others_posts' => 'edit_theme_options',
'edit_private_posts' => 'edit_theme_options',
'edit_published_posts' => 'edit_theme_options',
),
);

register_post_type( 'wp_navigation', $args );
Expand Down
93 changes: 47 additions & 46 deletions packages/block-library/src/navigation/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
Button,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { store as noticeStore } from '@wordpress/notices';

/**
* Internal dependencies
Expand All @@ -54,6 +53,7 @@ import NavigationMenuSelector from './navigation-menu-selector';
import NavigationMenuNameControl from './navigation-menu-name-control';
import UnsavedInnerBlocks from './unsaved-inner-blocks';
import NavigationMenuDeleteControl from './navigation-menu-delete-control';
import useNavigationNotice from './use-navigation-notice';

const EMPTY_ARRAY = [];

Expand Down Expand Up @@ -107,8 +107,6 @@ function Navigation( {
customPlaceholder: CustomPlaceholder = null,
customAppender: CustomAppender = null,
} ) {
const noticeRef = useRef();

const {
openSubmenusOnClick,
overlayMenu,
Expand Down Expand Up @@ -192,8 +190,6 @@ function Navigation( {
__unstableMarkNextChangeAsNotPersistent,
} = useDispatch( blockEditorStore );

const { createWarningNotice, removeNotice } = useDispatch( noticeStore );

const [
hasSavedUnsavedInnerBlocks,
setHasSavedUnsavedInnerBlocks,
Expand All @@ -220,6 +216,8 @@ function Navigation( {
hasResolvedCanUserUpdateNavigationEntity,
canUserDeleteNavigationEntity,
hasResolvedCanUserDeleteNavigationEntity,
canUserCreateNavigation,
hasResolvedCanUserCreateNavigation,
} = useNavigationMenu( ref );

const navRef = useRef();
Expand Down Expand Up @@ -307,7 +305,7 @@ function Navigation( {
setDetectedColor,
setDetectedBackgroundColor
);
const subMenuElement = navRef.current.querySelector(
const subMenuElement = navRef.current?.querySelector(
'[data-type="core/navigation-link"] [data-type="core/navigation-link"]'
);
if ( subMenuElement ) {
Expand Down Expand Up @@ -336,52 +334,52 @@ function Navigation( {
}
}, [ clientId, ref, hasUncontrolledInnerBlocks, controlledInnerBlocks ] );

useEffect( () => {
const setPermissionsNotice = () => {
if ( noticeRef.current ) {
return;
}

noticeRef.current =
'block-library/core/navigation/permissions/update';

createWarningNotice(
__(
'You do not have permission to edit this Menu. Any changes made will not be saved.'
),
{
id: noticeRef.current,
type: 'snackbar',
}
);
};
const [ showCantEditNotice, hideCantEditNotice ] = useNavigationNotice( {
name: 'block-library/core/navigation/permissions/update',
message: __(
'You do not have permission to edit this Menu. Any changes made will not be saved.'
),
} );

const removePermissionsNotice = () => {
if ( ! noticeRef.current ) {
return;
}
removeNotice( noticeRef.current );
noticeRef.current = null;
};
const [ showCantCreateNotice, hideCantCreateNotice ] = useNavigationNotice(
{
name: 'block-library/core/navigation/permissions/create',
message: __(
'You do not have permission to create Navigation Menus.'
),
}
);

useEffect( () => {
if ( ! isSelected && ! isInnerBlockSelected ) {
removePermissionsNotice();
hideCantEditNotice();
hideCantCreateNotice();
}

if (
( isSelected || isInnerBlockSelected ) &&
hasResolvedCanUserUpdateNavigationEntity &&
! canUserUpdateNavigationEntity
) {
setPermissionsNotice();
if ( isSelected || isInnerBlockSelected ) {
if (
hasResolvedCanUserUpdateNavigationEntity &&
! canUserUpdateNavigationEntity
) {
showCantEditNotice();
}

if (
! ref &&
hasResolvedCanUserCreateNavigation &&
! canUserCreateNavigation
) {
showCantCreateNotice();
}
}
}, [
ref,
isEntityAvailable,
hasResolvedCanUserUpdateNavigationEntity,
canUserUpdateNavigationEntity,
isSelected,
isInnerBlockSelected,
canUserUpdateNavigationEntity,
hasResolvedCanUserUpdateNavigationEntity,
canUserCreateNavigation,
hasResolvedCanUserCreateNavigation,
ref,
] );

const startWithEmptyMenu = useCallback( () => {
Expand Down Expand Up @@ -488,6 +486,7 @@ function Navigation( {
onClose();
} }
onCreateNew={ startWithEmptyMenu }
showCreate={ canUserCreateNavigation }
/>
) }
</ToolbarDropdownMenu>
Expand Down Expand Up @@ -642,11 +641,13 @@ function Navigation( {
hasResolvedNavigationMenus
}
clientId={ clientId }
canUserCreateNavigation={ canUserCreateNavigation }
/>
) }
{ ! isEntityAvailable && ! isPlaceholderShown && (
<PlaceholderPreview isLoading />
) }
{ ! hasResolvedCanUserCreateNavigation ||
( ! isEntityAvailable && ! isPlaceholderShown && (
<PlaceholderPreview isLoading />
) ) }
{ ! isPlaceholderShown && (
<ResponsiveWrapper
id={ clientId }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import { addQueryArgs } from '@wordpress/url';
*/
import useNavigationMenu from '../use-navigation-menu';

export default function NavigationMenuSelector( { onSelect, onCreateNew } ) {
export default function NavigationMenuSelector( {
onSelect,
onCreateNew,
showCreate = false,
} ) {
const { navigationMenus } = useNavigationMenu();
const ref = useEntityId( 'postType', 'wp_navigation' );

Expand Down Expand Up @@ -42,18 +46,20 @@ export default function NavigationMenuSelector( { onSelect, onCreateNew } ) {
} ) }
/>
</MenuGroup>
<MenuGroup>
<MenuItem onClick={ onCreateNew }>
{ __( 'Create new menu' ) }
</MenuItem>
<MenuItem
href={ addQueryArgs( 'edit.php', {
post_type: 'wp_navigation',
} ) }
>
{ __( 'Manage menus' ) }
</MenuItem>
</MenuGroup>
{ showCreate && (
<MenuGroup>
<MenuItem onClick={ onCreateNew }>
{ __( 'Create new menu' ) }
</MenuItem>
<MenuItem
href={ addQueryArgs( 'edit.php', {
post_type: 'wp_navigation',
} ) }
>
{ __( 'Manage menus' ) }
</MenuItem>
</MenuGroup>
) }
</>
);
}
64 changes: 40 additions & 24 deletions packages/block-library/src/navigation/edit/placeholder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const ExistingMenusDropdown = ( {
onFinish,
menus,
onCreateFromMenu,
showClassicMenus = false,
} ) => {
const toggleProps = {
variant: 'tertiary',
Expand Down Expand Up @@ -65,22 +66,24 @@ const ExistingMenusDropdown = ( {
);
} ) }
</MenuGroup>
<MenuGroup label={ __( 'Classic Menus' ) }>
{ menus?.map( ( menu ) => {
return (
<MenuItem
onClick={ () => {
setSelectedMenu( menu.id );
onCreateFromMenu( menu.name );
} }
onClose={ onClose }
key={ menu.id }
>
{ decodeEntities( menu.name ) }
</MenuItem>
);
} ) }
</MenuGroup>
{ showClassicMenus && (
<MenuGroup label={ __( 'Classic Menus' ) }>
{ menus?.map( ( menu ) => {
return (
<MenuItem
onClick={ () => {
setSelectedMenu( menu.id );
onCreateFromMenu( menu.name );
} }
onClose={ onClose }
key={ menu.id }
>
{ decodeEntities( menu.name ) }
</MenuItem>
);
} ) }
</MenuGroup>
) }
</>
) }
</DropdownMenu>
Expand All @@ -92,6 +95,7 @@ export default function NavigationPlaceholder( {
onFinish,
canSwitchNavigationMenu,
hasResolvedNavigationMenus,
canUserCreateNavigation = false,
} ) {
const [ selectedMenu, setSelectedMenu ] = useState();
const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false );
Expand All @@ -102,6 +106,10 @@ export default function NavigationPlaceholder( {
blocks,
navigationMenuTitle = null
) => {
if ( ! canUserCreateNavigation ) {
return;
}

const navigationMenu = await createNavigationMenu(
navigationMenuTitle,
blocks
Expand Down Expand Up @@ -176,8 +184,10 @@ export default function NavigationPlaceholder( {
<Icon icon={ navigation } />{ ' ' }
{ __( 'Navigation' ) }
</div>

<hr />
{ hasMenus || navigationMenus.length ? (

{ hasMenus || navigationMenus?.length ? (
<>
<ExistingMenusDropdown
canSwitchNavigationMenu={
Expand All @@ -188,11 +198,14 @@ export default function NavigationPlaceholder( {
onFinish={ onFinish }
menus={ menus }
onCreateFromMenu={ onCreateFromMenu }
showClassicMenus={
canUserCreateNavigation
}
/>
<hr />
</>
) : undefined }
{ hasPages ? (
{ canUserCreateNavigation && hasPages ? (
<>
<Button
variant="tertiary"
Expand All @@ -203,12 +216,15 @@ export default function NavigationPlaceholder( {
<hr />
</>
) : undefined }
<Button
variant="tertiary"
onClick={ onCreateEmptyMenu }
>
{ __( 'Start empty' ) }
</Button>

{ canUserCreateNavigation && (
<Button
variant="tertiary"
onClick={ onCreateEmptyMenu }
>
{ __( 'Start empty' ) }
</Button>
) }
</div>
</div>
</Placeholder>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* WordPress dependencies
*/
import { useRef } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { store as noticeStore } from '@wordpress/notices';

function useNavigationNotice( { name, message } = {} ) {
const noticeRef = useRef();

const { createWarningNotice, removeNotice } = useDispatch( noticeStore );

const showNotice = () => {
if ( noticeRef.current ) {
return;
}

noticeRef.current = name;

createWarningNotice( message, {
id: noticeRef.current,
type: 'snackbar',
} );
};

const hideNotice = () => {
if ( ! noticeRef.current ) {
return;
}
removeNotice( noticeRef.current );
noticeRef.current = null;
};

return [ showNotice, hideNotice ];
}

export default useNavigationNotice;
1 change: 1 addition & 0 deletions packages/block-library/src/navigation/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ $color-control-label-height: 20px;
font-size: $default-font-size;
font-family: $default-font;
gap: $grid-unit-15 * 0.5;
align-items: center;

// Margins.
.components-dropdown,
Expand Down
Loading

0 comments on commit 33ec385

Please sign in to comment.