Skip to content
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core-commands/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@babel/runtime": "7.25.7",
"@wordpress/block-editor": "file:../block-editor",
"@wordpress/commands": "file:../commands",
"@wordpress/components": "29.12.0",
"@wordpress/compose": "file:../compose",
"@wordpress/core-data": "file:../core-data",
"@wordpress/data": "file:../data",
Expand Down
90 changes: 89 additions & 1 deletion packages/core-commands/src/admin-navigation-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
* WordPress dependencies
*/
import { useCommand, useCommandLoader } from '@wordpress/commands';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { plus } from '@wordpress/icons';
import { getPath } from '@wordpress/url';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { useCallback, useMemo } from '@wordpress/element';
import { store as noticesStore } from '@wordpress/notices';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { Dashicon } from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -18,6 +19,20 @@ import { unlock } from './lock-unlock';

const { useHistory } = unlock( routerPrivateApis );

const GLOBAL_SYSTEM_POST_TYPES = [
'post',
'page',
'attachment',
'nav_menu_item',
'wp_block',
'wp_template',
'wp_template_part',
'wp_global_styles',
'wp_navigation',
'wp_font_family',
'wp_font_face',
];

const getAddNewPageCommand = () =>
function useAddNewPageCommand() {
const isSiteEditor = getPath( window.location.href )?.includes(
Expand Down Expand Up @@ -87,6 +102,74 @@ const getAddNewPageCommand = () =>
};
};

const getAddNewCustomPostTypeCommands = () =>
function useAddNewCustomPostTypeCommands() {
const customPostTypes = useSelect( ( select ) => {
const { getPostTypes } = select( coreStore );
const postTypes = getPostTypes( { per_page: -1 } );

if ( ! postTypes ) {
return [];
}

// Filter to only include user-created custom post types
// Exclude system post types and core WordPress post types
const systemPostTypes = GLOBAL_SYSTEM_POST_TYPES;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need to consider so many post types?
I think the code below is sufficient:

const excludedPostTypes = [ 'post', 'page', 'attachment' ];

See:

const excludedPostTypes = [ 'attachment' ];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

got it, I will check it out.


return postTypes
?.filter(
( { viewable, slug } ) =>
viewable && ! systemPostTypes.includes( slug )
)
.sort( ( a, b ) => a.name.localeCompare( b.name ) );
}, [] );

const commands = useMemo( () => {
return customPostTypes.map( ( postType ) => {
const { slug, labels, icon } = postType;
const singularName =
labels?.singular_name || labels?.name || slug;
const commandLabel = sprintf(
// translators: %s: Post type name
__( 'Add new %s' ),
singularName
);

// Handle icon - convert dashicon strings to proper components
let iconComponent = plus;
if ( icon && typeof icon === 'string' ) {
// If it's a dashicon string (starts with 'dashicons-'), convert to Dashicon component
if ( icon.startsWith( 'dashicons-' ) ) {
const dashiconName = icon.replace( 'dashicons-', '' );
iconComponent = <Dashicon icon={ dashiconName } />;
} else {
// For other string icons, use plus as fallback
iconComponent = plus;
}
} else if ( icon && typeof icon === 'function' ) {
// If it's already a component, use it
iconComponent = icon;
}

return {
name: `core/add-new-${ slug }`,
label: commandLabel,
icon: iconComponent,
callback: () => {
document.location.assign(
`post-new.php?post_type=${ slug }`
);
},
};
} );
}, [ customPostTypes ] );

return {
isLoading: false,
commands,
};
};

export function useAdminNavigationCommands() {
useCommand( {
name: 'core/add-new-post',
Expand All @@ -101,4 +184,9 @@ export function useAdminNavigationCommands() {
name: 'core/add-new-page',
hook: getAddNewPageCommand(),
} );

useCommandLoader( {
name: 'core/add-new-custom-post-types',
hook: getAddNewCustomPostTypeCommands(),
} );
}
Loading