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

Full Site Editing: Introduce a template editing mode inside the post editor #26355

Merged
merged 21 commits into from
Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
24 changes: 24 additions & 0 deletions docs/designers-developers/developers/data/data-core-edit-post.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ _Returns_

- `boolean`: Whether there are metaboxes or not.

<a name="isEditingTemplate" href="#isEditingTemplate">#</a> **isEditingTemplate**

Returns true if the template editing mode is enabled.

_Parameters_

- _state_ `Object`: Global application state.

_Returns_

- `boolean`: Whether we're editing the template.

<a name="isEditorPanelEnabled" href="#isEditorPanelEnabled">#</a> **isEditorPanelEnabled**

Returns true if the given panel is enabled, or false otherwise. Panels are
Expand Down Expand Up @@ -381,6 +393,18 @@ _Parameters_

- _metaBoxesPerLocation_ `Object`: Meta boxes per location.

<a name="setIsEditingTemplate" href="#setIsEditingTemplate">#</a> **setIsEditingTemplate**

Returns an action object used to switch to template editing.

_Parameters_

- _value_ `boolean`: Is editing template.

_Returns_

- `Object`: Action object.

<a name="setIsInserterOpened" href="#setIsInserterOpened">#</a> **setIsInserterOpened**

Returns an action object used to open/close the inserter.
Expand Down
13 changes: 13 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,16 @@ function gutenberg_extend_block_editor_settings_with_default_editor_styles( $set
return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_settings_with_default_editor_styles' );

/**
* Adds a flag to the editor settings to know whether we're in FSE theme or not.
*
* @param array $settings Default editor settings.
*
* @return array Filtered editor settings.
*/
function gutenberg_extend_block_editor_settings_with_fse_theme_flag( $settings ) {
$settings['isFSETheme'] = gutenberg_is_fse_theme();
return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_settings_with_fse_theme_flag' );
3 changes: 0 additions & 3 deletions packages/base-styles/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ $z-layers: (
".edit-site-sidebar": 100000,
".edit-widgets-sidebar": 100000,
".edit-post-layout .edit-post-post-publish-panel": 100001,
// For larger views, the wp-admin navbar dropdown should be at top of
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
// the Publish Post sidebar.
".edit-post-layout .edit-post-post-publish-panel {greater than small}": 99998,

".entities-saved-states__panel": 100001,
// For larger views, the wp-admin navbar dropdown should be on top of
Expand Down
14 changes: 1 addition & 13 deletions packages/block-library/src/post-content/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';

/**
Expand All @@ -13,19 +12,8 @@ import PostContentInnerBlocks from './inner-blocks';
export default function PostContentEdit( {
context: { postId: contextPostId, postType: contextPostType },
} ) {
const { id: currentPostId, type: currentPostType } = useSelect(
( select ) => select( 'core/editor' ).getCurrentPost() ?? {}
);
Copy link
Contributor Author

@youknowriad youknowriad Nov 30, 2020

Choose a reason for hiding this comment

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

This reverts #24010 cc @Addison-Stavlo

It seems the checks were not good enough IMO. It relies on something that doesn't give us semantic information about the context but it was more an implementation detail.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I agree that these original checks were not great, but there simply wasn't another way to do it with the information available at the time. There didn't seem to be a super clear way to add the necessary information to the context either... The problem is really, given a global context with a postID, how do you prevent nested context consumers from rendering recursively infinitely?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems we need a context value to indicate the post content id we're currently rendering (and not just the "post id").

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not fixed entirely, but the important breakage in the template editor is fixed by 46724a8

const blockProps = useBlockProps();

// Only render InnerBlocks if the context is different from the active post
// to avoid infinite recursion of post content.
if (
contextPostId &&
contextPostType &&
contextPostId !== currentPostId &&
contextPostType !== currentPostType
) {
if ( contextPostId && contextPostType ) {
return (
<div { ...blockProps }>
<PostContentInnerBlocks
Expand Down
17 changes: 17 additions & 0 deletions packages/core-data/src/controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function regularFetch( url ) {
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
return {
type: 'REGULAR_FETCH',
url,
};
}
const controls = {
async REGULAR_FETCH( { url } ) {
const { data } = await window
.fetch( url )
.then( ( res ) => res.json() );

return data;
},
};

export default controls;
3 changes: 2 additions & 1 deletion packages/core-data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as actions from './actions';
import * as resolvers from './resolvers';
import * as locksSelectors from './locks/selectors';
import * as locksActions from './locks/actions';
import customControls from './controls';
import { defaultEntities, getMethodName } from './entities';
import { STORE_NAME } from './name';

Expand Down Expand Up @@ -58,7 +59,7 @@ const entityActions = defaultEntities.reduce( ( result, entity ) => {

const storeConfig = {
reducer,
controls,
controls: { ...customControls, ...controls },
actions: { ...actions, ...entityActions, ...locksActions },
selectors: { ...selectors, ...entitySelectors, ...locksSelectors },
resolvers: { ...resolvers, ...entityResolvers },
Expand Down
39 changes: 39 additions & 0 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import { addQueryArgs } from '@wordpress/url';
import deprecated from '@wordpress/deprecated';
import { controls } from '@wordpress/data';
import { apiFetch } from '@wordpress/data-controls';
/**
* Internal dependencies
*/
import { regularFetch } from './controls';

/**
* Internal dependencies
Expand Down Expand Up @@ -382,3 +386,38 @@ export function* getAutosaves( postType, postId ) {
export function* getAutosave( postType, postId ) {
yield controls.resolveSelect( 'core', 'getAutosaves', postType, postId );
}

/**
* Retrieve the frontend template used for a given link.
*
* @param {string} link Link.
*/
export function* __experimentalGetTemplateForLink( link ) {
gziolo marked this conversation as resolved.
Show resolved Hide resolved
// Ideally this should be using an apiFetch call
// We could potentially do so by adding a "filter" to the `wp_template` end point.
// Also it seems the returned object is not a regular REST API post type.
const template = yield regularFetch(
addQueryArgs( link, {
'_wp-find-template': true,
} )
);

if ( template === null ) {
return;
}

yield getEntityRecord( 'postType', 'wp_template', template.ID );
const record = yield controls.select(
'core',
'getEntityRecord',
'postType',
'wp_template',
template.ID
);

if ( record ) {
yield receiveEntityRecords( 'postType', 'wp_template', [ record ], {
'find-template': link,
} );
}
}
16 changes: 16 additions & 0 deletions packages/core-data/src/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,3 +740,19 @@ export const getReferenceByDistinctEdits = createSelector(
state.undo.flattenedUndo,
]
);

/**
* Retrieve the frontend template used for a given link.
*
* @param {Object} state Editor state.
* @param {string} link Link.
*
* @return {Object?} The template record.
*/
export function __experimentalGetTemplateForLink( state, link ) {
const records = getEntityRecords( state, 'postType', 'wp_template', {
'find-template': link,
} );

return records?.length ? records[ 0 ] : null;
}
12 changes: 12 additions & 0 deletions packages/e2e-test-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,18 @@ Clicks on the button in the header which opens Document Settings sidebar when it

Opens the global block inserter.

<a name="openPreviewPage" href="#openPreviewPage">#</a> **openPreviewPage**

Opens the preview page of an edited post.

_Parameters_

- _editorPage_ `Page`: puppeteer editor page.

_Returns_

- `Page`: preview page.

<a name="openPublishPanel" href="#openPublishPanel">#</a> **openPublishPanel**

Opens the publish panel.
Expand Down
1 change: 1 addition & 0 deletions packages/e2e-test-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,6 @@ export { uninstallPlugin } from './uninstall-plugin';
export { visitAdminPage } from './visit-admin-page';
export { waitForWindowDimensions } from './wait-for-window-dimensions';
export { showBlockToolbar } from './show-block-toolbar';
export { openPreviewPage } from './preview';

export * from './mocks';
33 changes: 33 additions & 0 deletions packages/e2e-test-utils/src/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* External dependencies
*/
import { last } from 'lodash';

/** @typedef {import('puppeteer').Page} Page */

/**
* Opens the preview page of an edited post.
*
* @param {Page} editorPage puppeteer editor page.
* @return {Page} preview page.
*/
export async function openPreviewPage( editorPage = page ) {
let openTabs = await browser.pages();
const expectedTabsCount = openTabs.length + 1;
await editorPage.click( '.block-editor-post-preview__button-toggle' );
await editorPage.waitFor( '.edit-post-header-preview__button-external' );
await editorPage.click( '.edit-post-header-preview__button-external' );

// Wait for the new tab to open.
while ( openTabs.length < expectedTabsCount ) {
await editorPage.waitFor( 1 );
openTabs = await browser.pages();
}

const previewPage = last( openTabs );
// Wait for the preview to load. We can't do interstitial detection here,
// because it might load too quickly for us to pick up, so we wait for
// the preview to load by waiting for the title to appear.
await previewPage.waitForSelector( '.entry-title' );
return previewPage;
}
54 changes: 0 additions & 54 deletions packages/e2e-tests/config/setup-debug-artifacts.js
Original file line number Diff line number Diff line change
@@ -1,54 +0,0 @@
/**
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
* External dependencies
*/
const fs = require( 'fs' );
const util = require( 'util' );
const root = process.env.GITHUB_WORKSPACE || process.cwd();
const ARTIFACTS_PATH = root + '/artifacts';

const writeFile = util.promisify( fs.writeFile );

if ( ! fs.existsSync( ARTIFACTS_PATH ) ) {
fs.mkdirSync( ARTIFACTS_PATH );
}

/**
* Gutenberg uses the default jest-jasmine2 test runner that comes with Jest.
* Unfortunately, version 2 of jasmine doesn't support async reporters. It
* does support async before and after hooks though, so the workaround here
* works by making each test wait for the artifacts before starting.
*
* Kudos to Tom Esterez (@testerez) for sharing this idea in https://github.com/smooth-code/jest-puppeteer/issues/131#issuecomment-424073620
*/
let artifactsPromise;
// eslint-disable-next-line jest/no-jasmine-globals
jasmine.getEnv().addReporter( {
specDone: ( result ) => {
if ( result.status === 'failed' ) {
artifactsPromise = storeArtifacts( result.fullName );
}
},
} );

beforeEach( () => artifactsPromise );
afterAll( () => artifactsPromise );

async function storeArtifacts( testName ) {
const slug = slugify( testName );
await writeFile(
`${ ARTIFACTS_PATH }/${ slug }-snapshot.html`,
await page.content()
);
await page.screenshot( { path: `${ ARTIFACTS_PATH }/${ slug }.jpg` } );
}

function slugify( testName ) {
const datetime = new Date().toISOString().split( '.' )[ 0 ];
const readableName = `${ testName } ${ datetime }`;
const slug = readableName
.toLowerCase()
.replace( /:/g, '-' )
.replace( /[^0-9a-zA-Z \-\(\)]/g, '' )
.replace( / /g, '-' );
return slug;
}
27 changes: 1 addition & 26 deletions packages/e2e-tests/specs/editor/various/preview.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* External dependencies
*/
import { last } from 'lodash';

/**
* WordPress dependencies
*/
Expand All @@ -15,31 +10,11 @@ import {
deactivatePlugin,
publishPost,
saveDraft,
openPreviewPage,
} from '@wordpress/e2e-test-utils';

/** @typedef {import('puppeteer').Page} Page */

async function openPreviewPage( editorPage ) {
let openTabs = await browser.pages();
const expectedTabsCount = openTabs.length + 1;
await editorPage.click( '.block-editor-post-preview__button-toggle' );
await editorPage.waitFor( '.edit-post-header-preview__button-external' );
await editorPage.click( '.edit-post-header-preview__button-external' );

// Wait for the new tab to open.
while ( openTabs.length < expectedTabsCount ) {
await editorPage.waitFor( 1 );
openTabs = await browser.pages();
}

const previewPage = last( openTabs );
// Wait for the preview to load. We can't do interstitial detection here,
// because it might load too quickly for us to pick up, so we wait for
// the preview to load by waiting for the title to appear.
await previewPage.waitForSelector( '.entry-title' );
return previewPage;
}

/**
* Given the Page instance for the editor, opens preview drodpdown, and
* awaits the presence of the external preview selector.
Expand Down
Loading