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

Posts list powered by DataViews #62705

Merged
merged 13 commits into from
Jul 1, 2024
62 changes: 59 additions & 3 deletions lib/experimental/posts/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,78 @@

add_action( 'admin_menu', 'gutenberg_replace_posts_dashboard' );

// Default to is-fullscreen-mode to avoid jumps in the UI.
add_filter(
'admin_body_class',
static function ( $classes ) {
Copy link
Member

Choose a reason for hiding this comment

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

Normally anonymous functions are not recommended in core, because they don't allow a third-party plugin to use remove_filter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's what we do for site editor in core right now. I'll have to check if I can add the filter only in this new page though.. I didn't observe something weird so far though..

Copy link
Member

Choose a reason for hiding this comment

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

Maybe the current one for site editor, passed during a code review but as far as I know anonymous functions should be avoided, they work well the issue is if a plugin wants to remove the filter the plugin can not do it.

return "$classes is-fullscreen-mode";
}
);

/**
* Renders the new posts dashboard page.
*/
function gutenberg_posts_dashboard() {
$block_editor_context = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) );
$custom_settings = array(
'siteUrl' => site_url(),
'styles' => get_block_editor_theme_styles(),
'supportsLayout' => wp_theme_has_theme_json(),
);

$editor_settings = get_block_editor_settings( $custom_settings, $block_editor_context );
$active_global_styles_id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id();
$active_theme = get_stylesheet();

$preload_paths = array(
array( '/wp/v2/media', 'OPTIONS' ),
'/wp/v2/types?context=view',
'/wp/v2/global-styles/' . $active_global_styles_id . '?context=edit',
'/wp/v2/global-styles/' . $active_global_styles_id,
'/wp/v2/global-styles/themes/' . $active_theme,
);
block_editor_rest_api_preload( $preload_paths, $block_editor_context );

// Preload server-registered block schemas.
wp_add_inline_script(
'wp-blocks',
'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');'
);

/** This action is documented in wp-admin/edit-form-blocks.php */
do_action( 'enqueue_block_editor_assets' );
wp_register_style(
'wp-gutenberg-posts-dashboard',
gutenberg_url( 'build/edit-site/posts.css', __FILE__ ),
array( 'wp-components', 'wp-commands' )
array( 'wp-components', 'wp-commands', 'wp-edit-site' )
);
wp_enqueue_style( 'wp-gutenberg-posts-dashboard' );
wp_add_inline_script( 'wp-edit-site', 'window.wp.editSite.initializePostsDashboard( "gutenberg-posts-dashboard" );', 'after' );
wp_add_inline_script(
'wp-edit-site',
sprintf(
'wp.domReady( function() {
wp.editSite.initializePostsDashboard( "gutenberg-posts-dashboard", %s );
} );',
wp_json_encode( $editor_settings )
)
);
wp_enqueue_script( 'wp-edit-site' );

wp_enqueue_media();
echo '<div id="gutenberg-posts-dashboard"></div>';
}

/**
* Redirects to the new posts dashboard page and adds the postType query arg.
Copy link
Member

Choose a reason for hiding this comment

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

Instead of doing a redirect to include the post type. Could we assume a default post-type? e.g: if empty( $_GET['postType'] ) we assume it has the value post on our code?
The current post list seems to work like that it does not have a postType parameter in case of post.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to have the param in the URL for the editor to resolve the current entities etc..

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we could have a small js code on loading adding postType=post with history.push({postType:'post'}) if a postType is not set.

*/
function gutenberg_add_post_type_arg() {
global $pagenow;
if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'gutenberg-posts-dashboard' === $_GET['page'] && empty( $_GET['postType'] ) ) {
wp_redirect( admin_url( '/admin.php?page=gutenberg-posts-dashboard&postType=post' ) );
exit;
}
}
add_action( 'admin_init', 'gutenberg_add_post_type_arg' );

/**
* Replaces the default posts menu item with the new posts dashboard.
*/
Expand Down
21 changes: 4 additions & 17 deletions packages/dataviews/src/dataviews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import Filters from './filters';
import Search from './search';
import { LAYOUT_TABLE, LAYOUT_GRID } from './constants';
import { VIEW_LAYOUTS } from './layouts';
import BulkActions from './bulk-actions';
import {
default as BulkActions,
useSomeItemHasAPossibleBulkAction,
} from './bulk-actions';
import { normalizeFields } from './normalize-fields';
import BulkActionsToolbar from './bulk-actions-toolbar';
import type { Action, Field, View, ViewBaseProps } from './types';
Expand Down Expand Up @@ -51,22 +54,6 @@ const defaultGetItemId = ( item: ItemWithId ) => item.id;

const defaultOnSelectionChange = () => {};

function useSomeItemHasAPossibleBulkAction< Item >(
ntsekouras marked this conversation as resolved.
Show resolved Hide resolved
actions: Action< Item >[],
data: Item[]
) {
return useMemo( () => {
return data.some( ( item ) => {
return actions.some( ( action ) => {
return (
action.supportsBulk &&
( ! action.isEligible || action.isEligible( item ) )
);
} );
} );
}, [ actions, data ] );
}

export default function DataViews< Item >( {
view,
onChangeView,
Expand Down
8 changes: 1 addition & 7 deletions packages/dataviews/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@
text-transform: uppercase;
font-weight: 500;

&:has(.dataviews-view-table-header-button) {
&:has(.dataviews-view-table-header-button):not(:first-child) {
padding-left: $grid-unit-05;
}
}
Expand Down Expand Up @@ -263,7 +263,6 @@
color: $gray-700;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
width: 100%;

a {
Expand Down Expand Up @@ -332,11 +331,6 @@
.dataviews-view-grid__fields .dataviews-view-grid__field .dataviews-view-grid__field-value {
color: $gray-900;
}

.page-pages-preview-field__button::after {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
background: rgba(var(--wp-admin-theme-color--rgb), 0.04);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,50 @@ import {
TextControl,
} from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { useDispatch, useRegistry } from '@wordpress/data';
import { useDispatch, useRegistry, useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { store as coreStore } from '@wordpress/core-data';
import { store as noticesStore } from '@wordpress/notices';
import { decodeEntities } from '@wordpress/html-entities';
import { serialize, synchronizeBlocksWithTemplate } from '@wordpress/blocks';

export default function AddNewPageModal( { onSave, onClose } ) {
const [ isCreatingPage, setIsCreatingPage ] = useState( false );
export default function AddNewPostModal( { postType, onSave, onClose } ) {
const labels = useSelect(
( select ) => select( coreStore ).getPostType( postType )?.labels,
[ postType ]
);
const [ isCreatingPost, setIsCreatingPost ] = useState( false );
const [ title, setTitle ] = useState( '' );

const { saveEntityRecord } = useDispatch( coreStore );
const { createErrorNotice, createSuccessNotice } =
useDispatch( noticesStore );
const { resolveSelect } = useRegistry();

async function createPage( event ) {
async function createPost( event ) {
event.preventDefault();

if ( isCreatingPage ) {
if ( isCreatingPost ) {
return;
}
setIsCreatingPage( true );
setIsCreatingPost( true );
try {
const pagePostType =
await resolveSelect( coreStore ).getPostType( 'page' );
const postTypeObject =
await resolveSelect( coreStore ).getPostType( postType );
const newPage = await saveEntityRecord(
'postType',
'page',
postType,
{
status: 'draft',
title,
slug: title || __( 'No title' ),
content:
!! pagePostType.template && pagePostType.template.length
!! postTypeObject.template &&
postTypeObject.template.length
? serialize(
synchronizeBlocksWithTemplate(
[],
pagePostType.template
postTypeObject.template
)
)
: undefined,
Expand All @@ -59,40 +64,41 @@ export default function AddNewPageModal( { onSave, onClose } ) {

createSuccessNotice(
sprintf(
// translators: %s: Title of the created template e.g: "Category".
// translators: %s: Title of the created post e.g: "Hello world".
__( '"%s" successfully created.' ),
decodeEntities( newPage.title?.rendered || title )
),
{
type: 'snackbar',
}
{ type: 'snackbar' }
);
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __( 'An error occurred while creating the page.' );
: __( 'An error occurred while creating the item.' );

createErrorNotice( errorMessage, {
type: 'snackbar',
} );
} finally {
setIsCreatingPage( false );
setIsCreatingPost( false );
}
}

return (
<Modal
title={ __( 'Draft a new page' ) }
title={
// translators: %s: post type singular_name label e.g: "Page".
sprintf( __( 'Draft new: %s' ), labels?.singular_name )
}
onRequestClose={ onClose }
focusOnMount="firstContentElement"
size="small"
>
<form onSubmit={ createPage }>
<form onSubmit={ createPost }>
<VStack spacing={ 3 }>
<TextControl
__next40pxDefaultSize
label={ __( 'Page title' ) }
label={ __( 'Title' ) }
onChange={ setTitle }
placeholder={ __( 'No title' ) }
value={ title }
Expand All @@ -109,8 +115,8 @@ export default function AddNewPageModal( { onSave, onClose } ) {
__next40pxDefaultSize
variant="primary"
type="submit"
isBusy={ isCreatingPage }
aria-disabled={ isCreatingPage }
isBusy={ isCreatingPost }
aria-disabled={ isCreatingPost }
>
{ __( 'Create draft' ) }
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,35 +114,40 @@ function useNavigateToPreviousEntityRecord() {

export function useSpecificEditorSettings() {
const onNavigateToEntityRecord = useNavigateToEntityRecord();
const { templateSlug, canvasMode, settings, postWithTemplate } = useSelect(
( select ) => {
const {
getEditedPostType,
getEditedPostId,
getEditedPostContext,
getCanvasMode,
getSettings,
} = unlock( select( editSiteStore ) );
const { getEditedEntityRecord } = select( coreStore );
const usedPostType = getEditedPostType();
const usedPostId = getEditedPostId();
const _record = getEditedEntityRecord(
'postType',
usedPostType,
usedPostId
);
const _context = getEditedPostContext();
return {
templateSlug: _record.slug,
canvasMode: getCanvasMode(),
settings: getSettings(),
postWithTemplate: _context?.postId,
};
},
[]
);
const {
templateSlug,
canvasMode,
settings,
shouldUseTemplateAsDefaultRenderingMode,
} = useSelect( ( select ) => {
const {
getEditedPostType,
getEditedPostId,
getEditedPostContext,
getCanvasMode,
getSettings,
} = unlock( select( editSiteStore ) );
const { getEditedEntityRecord } = select( coreStore );
const usedPostType = getEditedPostType();
const usedPostId = getEditedPostId();
const _record = getEditedEntityRecord(
'postType',
usedPostType,
usedPostId
);
const _context = getEditedPostContext();
return {
templateSlug: _record.slug,
canvasMode: getCanvasMode(),
settings: getSettings(),
// TODO: The `postType` check should be removed when the default rendering mode per post type is merged.
// @see https://github.com/WordPress/gutenberg/pull/62304/
shouldUseTemplateAsDefaultRenderingMode:
_context?.postId && _context?.postType !== 'post',
};
}, [] );
const archiveLabels = useArchiveLabel( templateSlug );
const defaultRenderingMode = postWithTemplate
const defaultRenderingMode = shouldUseTemplateAsDefaultRenderingMode
? 'template-locked'
: 'post-only';
const onNavigateToPreviousEntityRecord =
Expand Down
24 changes: 19 additions & 5 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ import SiteEditorMoreMenu from '../more-menu';
import SiteIcon from '../site-icon';
import useEditorIframeProps from '../block-editor/use-editor-iframe-props';
import useEditorTitle from './use-editor-title';
import { useIsSiteEditorLoading } from '../layout/hooks';

const { Editor, BackButton } = unlock( editorPrivateApis );
const { useHistory } = unlock( routerPrivateApis );
const { useHistory, useLocation } = unlock( routerPrivateApis );
const { BlockKeyboardShortcuts } = unlock( blockLibraryPrivateApis );

export default function EditSiteEditor( { isLoading } ) {
export default function EditSiteEditor( { isPostsList = false } ) {
const { params } = useLocation();
const isLoading = useIsSiteEditorLoading();
const {
editedPostType,
editedPostId,
Expand Down Expand Up @@ -215,9 +218,20 @@ export default function EditSiteEditor( { isLoading } ) {
<Button
label={ __( 'Open Navigation' ) }
className="edit-site-layout__view-mode-toggle"
onClick={ () =>
setCanvasMode( 'view' )
}
onClick={ () => {
setCanvasMode( 'view' );
// TODO: this is a temporary solution to navigate to the posts list if we are
// come here through `posts list` and are in focus mode editing a template, template part etc..
if (
isPostsList &&
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's fine but we should be careful about not using this variable in a lot of places.

params?.focusMode
) {
history.push( {
page: 'gutenberg-posts-dashboard',
postType: 'post',
} );
}
} }
>
<SiteIcon className="edit-site-layout__view-mode-toggle-icon" />
</Button>
Expand Down
Loading
Loading