-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Update document.title when post title changes #1802
Conversation
editor/post-title/index.js
Outdated
@@ -119,6 +119,7 @@ export default connect( | |||
return { | |||
onUpdate( title ) { | |||
dispatch( editPost( { title } ) ); | |||
dispatch( editPostTitle( title ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we just rely on the editPost
action instead and this beeing a side-effect if the title
is in the edits
maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Done in 1dcd6f880af805344f503c1b1f2e9bdd604cbe63.
editor/selectors.js
Outdated
@@ -74,6 +74,17 @@ export function isEditedPostDirty( state ) { | |||
} | |||
|
|||
/** | |||
* Returns true if there are unsaved values for the current edit session and if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this function does the opposite right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Done in 1f6601a8568261ec92f8dabc8d2b853895e9abdc.
*/ | ||
export function isCleanNewPost( state ) { | ||
return ! isEditedPostDirty( state ) && isEditedPostNew( state ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add a unit test for this selector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Done in 1f6601a8568261ec92f8dabc8d2b853895e9abdc.
lib/register.php
Outdated
@@ -44,7 +44,7 @@ function gutenberg_menu() { | |||
|
|||
add_submenu_page( | |||
'gutenberg', | |||
__( 'New Post', 'gutenberg' ), | |||
__( 'Gutenberg ', 'gutenberg' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing space intentional?
editor/effects.js
Outdated
let originalDocumentTitle; | ||
|
||
function populateDocumentTitle( title, isCleanNew = false ) { | ||
if ( ! title.trim() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like some of this logic makes more sense in a selector, like getDocumentTitle
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 8cec2c9.
editor/effects.js
Outdated
if ( ! title.trim() ) { | ||
title = isCleanNew ? __( 'New post' ) : __( '(Untitled)' ); | ||
} | ||
if ( ! originalDocumentTitle ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of tracking this as inferred from the original title, should not the client be able to generate the desired title at any point in time, including when the editor first initializes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potentially. However, that would require that we export a template from PHP that we can use in JS. This was a quicker way to achieve that goal.
The Customizer implements this via:
- https://github.com/WordPress/wordpress-develop/blob/4.8.0/src/wp-includes/class-wp-customize-manager.php#L3630
- https://github.com/WordPress/wordpress-develop/blob/4.8.0/src/wp-admin/js/customize-controls.js#L3646-L3659
I don't feel it is entirely clear where we should be exporting data from PHP to JS generally.
editor/effects.js
Outdated
let originalDocumentTitle; | ||
|
||
function populateDocumentTitle( title, isCleanNew = false ) { | ||
if ( ! title.trim() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be using the trimmed title when assigning document.title
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unnecessary because document.title
has its whitespace automatically normalized: https://html.spec.whatwg.org/multipage/dom.html#document.title
editor/effects.js
Outdated
export default { | ||
RESET_POST( action, store ) { | ||
setTimeout( () => { // Next-tick to ensure action has been applied to state in store . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aduth This next-tick feels hacky, but I didn't see a reliable way to access the store with the action
applied to it without doing so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related: #1816 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative here is to not treat these as effects of the action, but rather handled by logic which has subscribed to store updates (e.g. a connect
ed component, or a store.subscribe
callback).
This is the approach we had taken in the Calypso editor. Basically: Instead of binding to the specific actions that we think would cause a change to the document title selector value, we instead re-run the selector any time any dispatch occurs, and if the result is different, apply the new title value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aduth check out the latest changes. It feels much better. I looked at the DocumentHead
component in Calypso and used it to inspire a DocumentTitle
component.
8cec2c9
to
3efc5b8
Compare
Rebased from 8cec2c9d and amended tests to use Jest API. |
Rebasing. Former |
3efc5b8
to
b142f8b
Compare
…schema in UPDATE_POST action
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to work well in my testing. I left a few minor comments to address if you wish.
Only other thought I have is: Do we really want the document title to be assigned as the post's title? Per #1737 and current editor behavior, seems "Edit Post" could work just as well. Was there any conversation or thoughts behind the choice to use post title?
editor/document-title/index.js
Outdated
} | ||
} | ||
|
||
render() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I think we should stick with convention to have render
be last method in component, roughly something like:
- Constructor
- Lifecycle
- Helper methods
- Render
editor/selectors.js
Outdated
return state.editor.edits.title === undefined | ||
? get( state.currentPost, 'title.raw' ) | ||
: state.editor.edits.title; | ||
const editedTitle = get( state.editor, 'edits.title' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few minor thoughts:
get
with string as the second argument is significantly slower than array alternative (benchmark)state.editor.edits
is always an object (based on reducer default value) and we don't needget
to test its truthiness, for a trivial performance improvement:state.editor.edits.title
- We should compose selectors vs. accessing state directly when possible, i.e.
getPostEdits
instead ofstate.editor.edits
,getCurrentPost
instead ofstate.currentPost
get
accepts a third argument for default value, so this could be expressed as a singlereturn
value, though maybe not as readable
editor/selectors.js
Outdated
export function getDocumentTitle( state ) { | ||
let title = getEditedPostTitle( state ); | ||
|
||
if ( ! title || '' === title.trim() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe getEditedPostTitle
should return an empty string as its default? In which case we could consolidate this as if ( ! title.trim() ) {
. Not sure if there's a performance benefit to testing truthiness before a trim, but readability benefit in testing in single pass.
Good point. In fact, I just assumed that “new post” would be replaced with the post title. I think I instinctively wanted to include the post title in the title because when you have multiple posts open in separate tabs, it is very annoying to easily identify the tab for the post you want to edit. Case in point with 4 tabs open for separate posts: So this PR fixes that usability issue. |
I'll fix up your other issues you pointed out. Thank you for reviewing. |
When the page is loading, the tab looks like:
The post title is then prepended to the original title that was output by PHP.
When clicking “New Post” link the tab looks like:
Upon typing “Initial” the tab is live updated to:
If the title is then cleared out, on a new post or an existing post, then the tab appears as:
Fixes #1737.