From b9c59348b24164ccd7b4c43304aef1c4a0551c23 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 23 Mar 2018 15:23:37 +1100 Subject: [PATCH 01/63] Remove the copy button, add the Change Permalinks button --- editor/components/post-permalink/index.js | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index c7c19f8b5e5a4c..d9d0aaa0e792ba 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -8,13 +8,14 @@ import { connect } from 'react-redux'; */ import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { Dashicon, ClipboardButton, Button } from '@wordpress/components'; +import { Dashicon, Button } from '@wordpress/components'; /** * Internal Dependencies */ import './style.scss'; import { isEditedPostNew, getEditedPostAttribute } from '../../store/selectors'; +import { getWPAdminURL } from '../../utils/url'; class PostPermalink extends Component { constructor() { @@ -43,7 +44,7 @@ class PostPermalink extends Component { } render() { - const { isNew, link } = this.props; + const { isNew, link, permalinkStructure } = this.props; if ( isNew || ! link ) { return null; } @@ -55,14 +56,15 @@ class PostPermalink extends Component { - - { this.state.showCopyConfirmation ? __( 'Copied!' ) : __( 'Copy' ) } - + { ! permalinkStructure && + + } ); } @@ -73,6 +75,8 @@ export default connect( return { isNew: isEditedPostNew( state ), link: getEditedPostAttribute( state, 'link' ), + + permalinkStructure: window.wpApiSettings.schema.permalink_structure, }; } )( PostPermalink ); From 4f1c501a64e64081bbbe0d7fa6e001ee6555c27f Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 23 Mar 2018 15:53:55 +1100 Subject: [PATCH 02/63] Display the sample permalink --- editor/components/post-permalink/index.js | 45 ++++++++++++++++++++++- lib/compat.php | 33 +++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index d9d0aaa0e792ba..cefa287236d17c 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Dashicon, Button } from '@wordpress/components'; +import { addQueryArgs } from '@wordpress/url'; /** * Internal Dependencies @@ -27,10 +28,39 @@ class PostPermalink extends Component { this.onFinishCopy = this.onFinishCopy.bind( this ); } + componentWillMount() { + if ( this.props.samplePermalinkData ) { + this.setState( { + samplePermalink: this.generatePermalink( this.props.samplePermalinkData[0], this.props.samplePermalinkData[1] ), + } ); + } + } + componentWillUnmount() { clearTimeout( this.dismissCopyConfirmation ); } + componentWillReceiveProps( nextProps ) { + console.log( nextProps ); + if ( this.props.samplePermalinkData !== nextProps.samplePermalinkData ) { + this.setState( { + samplePermalink: this.generatePermalink( nextProps.samplePermalinkData[0], nextProps.samplePermalinkData[1] ), + } ); + } + } + + /** + * Replace the %postname% and %pagename% tags in a sample permalink URL with actual values. + * + * @param {string} template Permalink structure to replace the tags in. + * @param {string} post_name The post slug to use in replacements. + * + * @return {string} Prepared permalink. + */ + generatePermalink( template, post_name ) { + return template.replace( /%(postname|pagename)%/, post_name ); + } + onCopy() { this.setState( { showCopyConfirmation: true, @@ -45,17 +75,27 @@ class PostPermalink extends Component { render() { const { isNew, link, permalinkStructure } = this.props; + const { samplePermalink } = this.state; + if ( isNew || ! link ) { return null; } + var hrefLink = link; + var displayLink = decodeURI( link ); + if ( samplePermalink ) { + hrefLink = addQueryArgs( hrefLink, { preview: true } ); + displayLink = samplePermalink; + } + return (
{ __( 'Permalink:' ) } - + { ! permalinkStructure && - { ! permalinkStructure && + { // Show the sample permalink when it isn't being editing. + ! editingPermalink && + + } + + { // When we're editing the permalink, show the edit form. + editingPermalink && +
+ + { samplePermalinkPrefix } + + this.setState( { editedPostName: e.target.value } ) } + required + /> + + { samplePermalinkSuffix } + + +
+ } + + { // When the site has pretty permalinks, and we're not currently editing, show the Edit button. + permalinkStructure && ! editingPermalink && + + } + + { // When the site doesn't have pretty permalinks, show a button to enable them. + ! permalinkStructure && } From 19aa275d838a7ee5ee72503ddbaa2217dc99faaf Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Sun, 25 Mar 2018 11:10:45 +1100 Subject: [PATCH 11/63] Move the permalink edit form to its own component. --- editor/components/post-permalink/editor.js | 112 +++++++++++++++++++++ editor/components/post-permalink/index.js | 112 +++------------------ editor/store/selectors.js | 26 +++++ 3 files changed, 152 insertions(+), 98 deletions(-) create mode 100644 editor/components/post-permalink/editor.js diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js new file mode 100644 index 00000000000000..ae320fc1095897 --- /dev/null +++ b/editor/components/post-permalink/editor.js @@ -0,0 +1,112 @@ +/** + * External dependencies + */ +import { connect } from 'react-redux'; + +/** + * WordPress dependencies + */ +import { Component } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { Button } from '@wordpress/components'; + +/** + * Internal Dependencies + */ +import './style.scss'; +import { getEditedPostAttribute } from '../../store/selectors'; +import { editPost } from '../../store/actions'; + +class PostPermalinkEditor extends Component { + constructor() { + super( ...arguments ); + + this.onSavePermalink = this.onSavePermalink.bind( this ); + } + + /** + * Returns the permalink parts to populate the form. + * + * @return {Object} The prefix, suffix, and postName for the form. + */ + getPermalinkParts() { + const [ template, postName ] = this.props.samplePermalinkData; + const [ samplePermalinkPrefix, samplePermalinkSuffix ] = template.split( /%(?:postname|pagename)%/ ); + + return { + samplePermalinkPrefix, + samplePermalinkSuffix, + postName, + }; + } + + onSavePermalink() { + const postName = this.state.editedPostName.replace( /\s+/g, '-' ); + const [ template, oldPostName ] = this.props.samplePermalinkData; + + if ( ! postName || postName === oldPostName ) { + return; + } + + this.props.editPost( { + slug: postName, + sample_permalink: [ template, postName ], + } ); + + this.setState( { + editedPostName: postName, + } ); + + this.props.onSave(); + } + + render() { + const { + samplePermalinkPrefix, + samplePermalinkSuffix, + postName, + } = this.getPermalinkParts(); + + return ( +
+
+ + { samplePermalinkPrefix } + + this.setState( { editedPostName: event.target.value } ) } + required + /> + + { samplePermalinkSuffix } + + +
+
+ ); + } +} + +export default connect( + ( state ) => { + return { + samplePermalinkData: getEditedPostAttribute( state, 'sample_permalink' ), + + permalinkStructure: window.wpApiSettings.schema.permalink_structure, + }; + }, + { + editPost, + } +)( PostPermalinkEditor ); + diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 3cfd7670db3359..04b922554f0eaa 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -8,14 +8,14 @@ import { connect } from 'react-redux'; */ import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { Dashicon, ClipboardButton, Button, Tooltip } from '@wordpress/components'; +import { Dashicon, Button, ClipboardButton, Tooltip } from '@wordpress/components'; /** * Internal Dependencies */ import './style.scss'; -import { isEditedPostNew, getEditedPostAttribute, getEditedPostPreviewLink } from '../../store/selectors'; -import { editPost } from '../../store/actions'; +import PostPermalinkEditor from './editor.js'; +import { isEditedPostNew, isPermalinkEditable, getEditedPostPreviewLink, getSamplePermalink } from '../../store/selectors'; import { getWPAdminURL } from '../../utils/url'; class PostPermalink extends Component { @@ -24,69 +24,13 @@ class PostPermalink extends Component { this.state = { iconClass: '', - samplePermalink: '', - samplePermalinkPrefix: '', - samplePermalinkSuffix: '', - postName: '', - editedPostName: '', editingPermalink: false, }; - - this.onSavePermalink = this.onSavePermalink.bind( this ); - } - - componentWillMount() { - if ( this.props.samplePermalinkData ) { - this.updateSamplePermalink( this.props.samplePermalinkData[ 0 ], this.props.samplePermalinkData[ 1 ] ); - } - } - - componentWillReceiveProps( nextProps ) { - if ( this.props.samplePermalinkData !== nextProps.samplePermalinkData ) { - this.updateSamplePermalink( nextProps.samplePermalinkData[ 0 ], nextProps.samplePermalinkData[ 1 ] ); - } - } - - /** - * Updates the samplePermalink data in the state. - * - * @param {string} template Permalink structure to replace the tags in. - * @param {string} postName The post slug to use in replacements. - */ - updateSamplePermalink( template, postName ) { - const regex = /%(?:postname|pagename)%/; - this.setState( { - samplePermalink: template.replace( regex, postName ), - samplePermalinkPrefix: template.split( regex )[ 0 ], - samplePermalinkSuffix: template.split( regex )[ 1 ], - postName: postName, - } ); - } - - onSavePermalink() { - const postName = this.state.editedPostName.replace( /\s+/g, '-' ); - - this.props.editPost( { - slug: postName, - sample_permalink: [ this.props.samplePermalinkData[ 0 ], postName ], - } ); - - this.setState( { - editingPermalink: false, - editedPostName: postName, - } ); } render() { - const { isNew, previewLink, permalinkStructure } = this.props; - const { - iconClass, - samplePermalink, - samplePermalinkPrefix, - samplePermalinkSuffix, - postName, - editingPermalink, - } = this.state; + const { isNew, previewLink, isEditable, samplePermalink } = this.props; + const { iconClass, editingPermalink } = this.state; if ( isNew || ! previewLink ) { return null; @@ -106,42 +50,19 @@ class PostPermalink extends Component { { __( 'Permalink:' ) } - { // Show the sample permalink when it isn't being editing. - ! editingPermalink && + { ! editingPermalink && } - { // When we're editing the permalink, show the edit form. - editingPermalink && -
- - { samplePermalinkPrefix } - - this.setState( { editedPostName: event.target.value } ) } - required - /> - - { samplePermalinkSuffix } - - -
+ { editingPermalink && + this.setState( { editingPermalink: false } ) } + /> } - { // When the site has pretty permalinks, and we're not currently editing, show the Edit button. - permalinkStructure && ! editingPermalink && + { isEditable && ! editingPermalink && } - { // When the site doesn't have pretty permalinks, show a button to enable them. - ! permalinkStructure && + { ! isEditable && - -
+
+ + { samplePermalinkPrefix } + + this.setState( { editedPostName: event.target.value } ) } + required + /> + + { samplePermalinkSuffix } + + +
); } } diff --git a/editor/components/post-permalink/style.scss b/editor/components/post-permalink/style.scss index 8bf288882366e8..d6a151f48bffaf 100644 --- a/editor/components/post-permalink/style.scss +++ b/editor/components/post-permalink/style.scss @@ -39,19 +39,42 @@ } } -.editor-post-permalink__edit-form { +.editor-post-permalink-editor { width: 100%; + min-width: 20%; + display: inline-flex; + align-items: center; + + // Higher specificity required to override core margin styles + .editor-post-permalink-editor__save { + margin-left: auto; + } } -.editor-post-permalink__prefix, -.editor-post-permalink__suffix { +.editor-post-permalink-editor__prefix { color: $dark-gray-300; + flex: initial; + min-width: 20%; + overflow: hidden; + position: relative; + white-space: nowrap; + + &:after { + @include long-content-fade( $size: 20% ); + } } -.editor-post-permalink__edit { +.editor-post-permalink-editor__edit { + flex: initial; + min-width: 20%; margin: 0 5px; } -.editor-post-permalink__save { - float: right; +.editor-post-permalink-editor__suffix { + color: $dark-gray-300; + margin-right: 10px; +} + +.editor-post-permalink-editor__save { + margin-left: auto; } From ab21ea564b52104a32ff9680efa34f8cbaca4187 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Sun, 25 Mar 2018 19:12:06 +1100 Subject: [PATCH 15/63] Check that we have a sample permalink before we try to use it. --- editor/store/selectors.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/editor/store/selectors.js b/editor/store/selectors.js index b0cc2987ba2977..ddec9809bcacae 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1527,6 +1527,10 @@ export function getProvisionalBlockUID( state ) { export function isPermalinkEditable( state ) { const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); + if ( ! samplePermalinkData || samplePermalinkData.length < 2 ) { + return false; + } + return /%(?:postname|pagename)%/.test( samplePermalinkData[ 0 ] ); } @@ -1540,5 +1544,9 @@ export function isPermalinkEditable( state ) { export function getSamplePermalink( state ) { const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); + if ( ! samplePermalinkData || samplePermalinkData.length < 2 ) { + return false; + } + return samplePermalinkData[ 0 ].replace( /%(?:postname|pagename)%/, samplePermalinkData[ 1 ] ); } From a0b9205e9d6deb9d162f365a2bf91ad0bc96aa10 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 26 Mar 2018 18:36:59 +1100 Subject: [PATCH 16/63] The sample_permalink is also the actual permalink for published posts. --- lib/compat.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/compat.php b/lib/compat.php index 3a9bd8ad62090e..ea40c117176bcc 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -447,15 +447,14 @@ function gutenberg_get_taxonomy_visibility_data( $object ) { * @return WP_REST_Response Response containing the sample_permalink, where appropriate. */ function gutenberg_add_sample_permalink_to_draft_posts( $response, $post, $request ) { - if ( empty( $response->data['status'] ) || 'draft' !== $response->data['status'] ) { - return $response; - } if ( 'edit' !== $request['context'] ) { return $response; } + if ( ! function_exists( 'get_sample_permalink' ) ) { require_once ABSPATH . '/wp-admin/includes/post.php'; } + $response->data['sample_permalink'] = get_sample_permalink( $post->ID ); return $response; } From 8523412394efb51631c77fae43be5753fa51c4d0 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 26 Mar 2018 18:53:06 +1100 Subject: [PATCH 17/63] Don't add a sample permlink for post types that aren't public. --- lib/compat.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/compat.php b/lib/compat.php index ea40c117176bcc..dd90a4046244e6 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -451,6 +451,10 @@ function gutenberg_add_sample_permalink_to_draft_posts( $response, $post, $reque return $response; } + if ( ! get_post_type_object( $post->post_type )->public ) { + return $response; + } + if ( ! function_exists( 'get_sample_permalink' ) ) { require_once ABSPATH . '/wp-admin/includes/post.php'; } From 4b0bce42e083c1e2f929931d3b9370c2516f5cab Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 26 Mar 2018 18:53:36 +1100 Subject: [PATCH 18/63] Move the PostPermalink component after the title editor. --- editor/components/post-title/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/components/post-title/index.js b/editor/components/post-title/index.js index c047748e8fd641..54c841ed05a79e 100644 --- a/editor/components/post-title/index.js +++ b/editor/components/post-title/index.js @@ -95,7 +95,6 @@ class PostTitle extends Component { return (
- { isSelected && } + { isSelected && }
); From edbbe9e9fc457d39412d6ad411becbb5f5e5ae81 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 26 Mar 2018 18:54:02 +1100 Subject: [PATCH 19/63] Make the permalink editor input autofocus when the form is opened. --- editor/components/post-permalink/editor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index c2e24bf7842982..ce9a7503ab3349 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -84,6 +84,7 @@ class PostPermalinkEditor extends Component { defaultValue={ postName } onChange={ ( event ) => this.setState( { editedPostName: event.target.value } ) } required + autoFocus /> { samplePermalinkSuffix } From d9a8440b3693edac080b551bf05dc5bafffffc49 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 26 Mar 2018 19:58:09 +1100 Subject: [PATCH 20/63] Move the permalink copy button later in the DOM, for better keyboard tabbing. --- components/clipboard-button/index.js | 4 ++-- editor/components/post-permalink/index.js | 20 ++++++++++---------- editor/components/post-permalink/style.scss | 4 ++++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/components/clipboard-button/index.js b/components/clipboard-button/index.js index 79f550acc60cb6..cd602656ef1ea8 100644 --- a/components/clipboard-button/index.js +++ b/components/clipboard-button/index.js @@ -81,8 +81,8 @@ class ClipboardButton extends Component { const classes = classnames( 'components-clipboard-button', className ); return ( - - diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 04b922554f0eaa..47aef872213d68 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -38,16 +38,6 @@ class PostPermalink extends Component { return (
- - this.setState( { iconClass: 'is-copied' } ) } - > - - - - { __( 'Permalink:' ) } { ! editingPermalink && @@ -71,6 +61,16 @@ class PostPermalink extends Component { } + + this.setState( { iconClass: 'is-copied' } ) } + > + + + + { ! isEditable && } - + Date: Tue, 27 Mar 2018 13:38:57 +1100 Subject: [PATCH 23/63] Revert "Move the permalink copy button later in the DOM, for better keyboard tabbing." This reverts commit 996fd9a4688ae4d2d9b9245daafd6483b4432473. --- components/clipboard-button/index.js | 4 ++-- editor/components/post-permalink/index.js | 20 ++++++++++---------- editor/components/post-permalink/style.scss | 4 ---- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/components/clipboard-button/index.js b/components/clipboard-button/index.js index cd602656ef1ea8..79f550acc60cb6 100644 --- a/components/clipboard-button/index.js +++ b/components/clipboard-button/index.js @@ -81,8 +81,8 @@ class ClipboardButton extends Component { const classes = classnames( 'components-clipboard-button', className ); return ( - - diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 3fae87417bac7f..c647121716a3e5 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -38,6 +38,16 @@ class PostPermalink extends Component { return (
+ + this.setState( { iconClass: 'is-copied' } ) } + > + + + + { __( 'Permalink:' ) } { ! editingPermalink && @@ -61,16 +71,6 @@ class PostPermalink extends Component { } - - this.setState( { iconClass: 'is-copied' } ) } - > - - - - { ! isEditable && } From 3ea14815eac54a0437db8eabf2173128071290b8 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 11:08:10 +1000 Subject: [PATCH 30/63] Use the edited post name as the form text input value. --- editor/components/post-permalink/editor.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index d816ce5cf1d46d..d7f9156896c751 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -35,12 +35,13 @@ class PostPermalinkEditor extends Component { */ getPermalinkParts() { const [ template, postName ] = this.props.samplePermalinkData; + const { editedPostName } = this.state; const [ samplePermalinkPrefix, samplePermalinkSuffix ] = template.split( /%(?:postname|pagename)%/ ); return { samplePermalinkPrefix, samplePermalinkSuffix, - postName, + editedPostName: editedPostName || postName, }; } @@ -70,7 +71,7 @@ class PostPermalinkEditor extends Component { const { samplePermalinkPrefix, samplePermalinkSuffix, - postName, + editedPostName, } = this.getPermalinkParts(); /* eslint-disable jsx-a11y/no-autofocus */ @@ -85,7 +86,7 @@ class PostPermalinkEditor extends Component { this.setState( { editedPostName: event.target.value } ) } required autoFocus From 71a29c71b6b980b9302ee09038e3eec12db11d6d Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 11:10:29 +1000 Subject: [PATCH 31/63] Replace connect() with withSelect() --- editor/components/post-permalink/editor.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index d7f9156896c751..51dc688613df8c 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -1,12 +1,7 @@ -/** - * External dependencies - */ -import { connect } from 'react-redux'; - /** * WordPress dependencies */ -import { withDispatch } from '@wordpress/data'; +import { withDispatch, withSelect } from '@wordpress/data'; import { Component, compose } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Button } from '@wordpress/components'; @@ -15,7 +10,6 @@ import { Button } from '@wordpress/components'; * Internal Dependencies */ import './style.scss'; -import { getEditedPostAttribute } from '../../store/selectors'; class PostPermalinkEditor extends Component { constructor() { @@ -107,9 +101,10 @@ class PostPermalinkEditor extends Component { } export default compose( [ - connect( ( state ) => { + withSelect( ( select ) => { + const { getEditedPostAttribute } = select( 'core/editor' ); return { - samplePermalinkData: getEditedPostAttribute( state, 'sample_permalink' ), + samplePermalinkData: getEditedPostAttribute( 'sample_permalink' ), }; } ), withDispatch( ( dispatch ) => { From c13585169250dfc1476f36f0f0f26d6ac7e68b35 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 11:22:41 +1000 Subject: [PATCH 32/63] Use the Button isLarge property, instead of the button class. --- editor/components/post-permalink/editor.js | 3 ++- editor/components/post-permalink/index.js | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index 51dc688613df8c..954f73ab59bd37 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -89,7 +89,8 @@ class PostPermalinkEditor extends Component { { samplePermalinkSuffix }
); @@ -123,10 +125,19 @@ class PostTitle extends Component { } const applyWithSelect = withSelect( ( select ) => { - const { getEditedPostAttribute } = select( 'core/editor' ); + const { getEditedPostAttribute, getCurrentPostType } = select( 'core/editor' ); return { title: getEditedPostAttribute( 'title' ), + postTypeSlug: getCurrentPostType(), + }; +} ); + +const applyWithAPIData = withAPIData( ( props ) => { + const { postTypeSlug } = props; + + return { + postType: `/wp/v2/types/${ postTypeSlug }?context=edit`, }; } ); @@ -160,6 +171,7 @@ const applyEditorSettings = withContext( 'editor' )( export default compose( applyWithSelect, + applyWithAPIData, applyWithDispatch, applyEditorSettings, withInstanceId, From 6f796fbc8462338481989477484da8312ad63324 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 12:12:03 +1000 Subject: [PATCH 37/63] Remove some old permalink data validity checks --- editor/store/selectors.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/editor/store/selectors.js b/editor/store/selectors.js index ddec9809bcacae..b0cc2987ba2977 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1527,10 +1527,6 @@ export function getProvisionalBlockUID( state ) { export function isPermalinkEditable( state ) { const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); - if ( ! samplePermalinkData || samplePermalinkData.length < 2 ) { - return false; - } - return /%(?:postname|pagename)%/.test( samplePermalinkData[ 0 ] ); } @@ -1544,9 +1540,5 @@ export function isPermalinkEditable( state ) { export function getSamplePermalink( state ) { const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); - if ( ! samplePermalinkData || samplePermalinkData.length < 2 ) { - return false; - } - return samplePermalinkData[ 0 ].replace( /%(?:postname|pagename)%/, samplePermalinkData[ 1 ] ); } From 02dea6c81cf3db424872c3e19c2c08c10c158d2e Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 12:13:20 +1000 Subject: [PATCH 38/63] Remove a redundant CSS block. --- editor/components/post-permalink/style.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/editor/components/post-permalink/style.scss b/editor/components/post-permalink/style.scss index 1de712e2db25eb..00b009efb48200 100644 --- a/editor/components/post-permalink/style.scss +++ b/editor/components/post-permalink/style.scss @@ -71,7 +71,3 @@ color: $dark-gray-300; margin-right: 10px; } - -.editor-post-permalink-editor__save { - margin-left: auto; -} From a02c4a08576fe27b1b5b86334ce7fe5efcaf9180 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 12:14:32 +1000 Subject: [PATCH 39/63] Remove some more redundant CSS. --- editor/components/post-permalink/style.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/editor/components/post-permalink/style.scss b/editor/components/post-permalink/style.scss index 00b009efb48200..23fb7446e89bde 100644 --- a/editor/components/post-permalink/style.scss +++ b/editor/components/post-permalink/style.scss @@ -53,7 +53,6 @@ .editor-post-permalink-editor__prefix { color: $dark-gray-300; - flex: initial; min-width: 20%; overflow: hidden; position: relative; @@ -62,7 +61,6 @@ } .editor-post-permalink-editor__edit { - flex: initial; min-width: 20%; margin: 0 5px; } From 5e6baab5aadf895c26cd94f4d8d1d37347a71f22 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 12:53:15 +1000 Subject: [PATCH 40/63] Fix some failing unit tests. --- phpunit/class-rest-blocks-controller-test.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpunit/class-rest-blocks-controller-test.php b/phpunit/class-rest-blocks-controller-test.php index f29ff5c2f767cb..8ae9b669f386bc 100644 --- a/phpunit/class-rest-blocks-controller-test.php +++ b/phpunit/class-rest-blocks-controller-test.php @@ -124,7 +124,7 @@ public function test_create_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( + $this->assertArraySubset( array( 'id' => self::$post_id, 'title' => 'New cool block', @@ -150,7 +150,7 @@ public function test_update_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( + $this->assertArraySubset( array( 'id' => self::$post_id, 'title' => 'Updated cool block', @@ -170,7 +170,7 @@ public function test_delete_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( + $this->assertArraySubset( array( 'deleted' => true, 'previous' => array( From c40194872551bf3b3d63bf9d45bdc05a4272845b Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 9 Apr 2018 13:42:51 +1000 Subject: [PATCH 41/63] lov2work w/ old phpunit --- phpunit/class-rest-blocks-controller-test.php | 59 +++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/phpunit/class-rest-blocks-controller-test.php b/phpunit/class-rest-blocks-controller-test.php index 8ae9b669f386bc..bafcb2b31b6a7d 100644 --- a/phpunit/class-rest-blocks-controller-test.php +++ b/phpunit/class-rest-blocks-controller-test.php @@ -124,13 +124,16 @@ public function test_create_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertArraySubset( - array( - 'id' => self::$post_id, - 'title' => 'New cool block', - 'content' => '

Wow!

', - ), $response->get_data() - ); + + $data = $response->get_data(); + + $this->assertArrayHasKey( 'id', $data ); + $this->assertArrayHasKey( 'title', $data ); + $this->assertArrayHasKey( 'content', $data ); + + $this->assertEquals( self::$post_id, $data['id'] ); + $this->assertEquals( 'New cool block', $data['title'] ); + $this->assertEquals( '

Wow!

', $data['content'] ); } /** @@ -150,13 +153,16 @@ public function test_update_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertArraySubset( - array( - 'id' => self::$post_id, - 'title' => 'Updated cool block', - 'content' => '

Nice!

', - ), $response->get_data() - ); + + $data = $response->get_data(); + + $this->assertArrayHasKey( 'id', $data ); + $this->assertArrayHasKey( 'title', $data ); + $this->assertArrayHasKey( 'content', $data ); + + $this->assertEquals( self::$post_id, $data['id'] ); + $this->assertEquals( 'Updated cool block', $data['title'] ); + $this->assertEquals( '

Nice!

', $data['content'] ); } /** @@ -170,16 +176,21 @@ public function test_delete_item() { $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); - $this->assertArraySubset( - array( - 'deleted' => true, - 'previous' => array( - 'id' => self::$post_id, - 'title' => 'My cool block', - 'content' => '

Hello!

', - ), - ), $response->get_data() - ); + + $data = $response->get_data(); + + $this->assertArrayHasKey( 'deleted', $data ); + $this->assertArrayHasKey( 'previous', $data ); + + $this->assertTrue( $data['deleted'] ); + + $this->assertArrayHasKey( 'id', $data['previous'] ); + $this->assertArrayHasKey( 'title', $data['previous'] ); + $this->assertArrayHasKey( 'content', $data['previous'] ); + + $this->assertEquals( self::$post_id, $data['previous']['id'] ); + $this->assertEquals( 'My cool block', $data['previous']['title'] ); + $this->assertEquals( '

Hello!

', $data['previous']['content'] ); } /** From 65cf88e84172f37afd5c68e08c15c66b5a929fbc Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 14:36:16 +1000 Subject: [PATCH 42/63] Make the permalink display in the correct order in LTR languages. Duplicates a similar fix in the classic editor. --- editor/components/post-permalink/editor.js | 32 ++++++++++++---------- editor/components/post-permalink/index.js | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index 954f73ab59bd37..adfa7bc9ff9f71 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -73,20 +73,24 @@ class PostPermalinkEditor extends Component { return ( - - { samplePermalinkPrefix } - - this.setState( { editedPostName: event.target.value } ) } - required - autoFocus - /> - - { samplePermalinkSuffix } + onSubmit={ this.onSavePermalink } + > + + + { samplePermalinkPrefix } + + this.setState( { editedPostName: event.target.value } ) } + required + autoFocus + /> + + { samplePermalinkSuffix } + + ‎ } From b0be34ad34020bb2ac3d93a9d678bb79dce00c99 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 15:12:54 +1000 Subject: [PATCH 43/63] Rename `sample_permalink` to `permalink_template`, remove the duplication of the postname, and reshuffle the relevant code. --- editor/components/post-permalink/editor.js | 38 ++++++---------------- editor/components/post-permalink/index.js | 4 +-- editor/store/selectors.js | 36 ++++++++++++++++---- lib/compat.php | 7 ++-- 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index adfa7bc9ff9f71..10a17f90f36dfb 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -22,38 +22,19 @@ class PostPermalinkEditor extends Component { this.onSavePermalink = this.onSavePermalink.bind( this ); } - /** - * Returns the permalink parts to populate the form. - * - * @return {Object} The prefix, suffix, and postName for the form. - */ - getPermalinkParts() { - const [ template, postName ] = this.props.samplePermalinkData; - const { editedPostName } = this.state; - const [ samplePermalinkPrefix, samplePermalinkSuffix ] = template.split( /%(?:postname|pagename)%/ ); - - return { - samplePermalinkPrefix, - samplePermalinkSuffix, - editedPostName: editedPostName || postName, - }; - } - onSavePermalink( event ) { const postName = this.state.editedPostName.replace( /\s+/g, '-' ); - const [ template, oldPostName ] = this.props.samplePermalinkData; event.preventDefault(); this.props.onSave(); - if ( ! postName || postName === oldPostName ) { + if ( ! postName || postName === this.props.postName ) { return; } this.props.editPost( { slug: postName, - sample_permalink: [ template, postName ], } ); this.setState( { @@ -63,10 +44,11 @@ class PostPermalinkEditor extends Component { render() { const { - samplePermalinkPrefix, - samplePermalinkSuffix, - editedPostName, - } = this.getPermalinkParts(); + prefix, + suffix, + postName, + } = this.props.permalinkParts; + const editedPostName = this.state.editedPostName || postName; /* eslint-disable jsx-a11y/no-autofocus */ // Autofocus is allowed here, as this mini-UI is only loaded when the user clicks to open it. @@ -77,7 +59,7 @@ class PostPermalinkEditor extends Component { > - { samplePermalinkPrefix } + { prefix } - { samplePermalinkSuffix } + { suffix } @@ -107,9 +89,9 @@ class PostPermalinkEditor extends Component { export default compose( [ withSelect( ( select ) => { - const { getEditedPostAttribute } = select( 'core/editor' ); + const { getPermalinkParts } = select( 'core/editor' ); return { - samplePermalinkData: getEditedPostAttribute( 'sample_permalink' ), + permalinkParts: getPermalinkParts(), }; } ), withDispatch( ( dispatch ) => { diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 8c53833667c2b0..fbe96058b7c9d3 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -15,7 +15,7 @@ import { Dashicon, Button, ClipboardButton, Tooltip } from '@wordpress/component */ import './style.scss'; import PostPermalinkEditor from './editor.js'; -import { isEditedPostNew, isPermalinkEditable, getEditedPostPreviewLink, getSamplePermalink } from '../../store/selectors'; +import { isEditedPostNew, isPermalinkEditable, getEditedPostPreviewLink, getPermalink } from '../../store/selectors'; import { getWPAdminURL } from '../../utils/url'; class PostPermalink extends Component { @@ -106,7 +106,7 @@ export default connect( isNew: isEditedPostNew( state ), previewLink: getEditedPostPreviewLink( state ), isEditable: isPermalinkEditable( state ), - samplePermalink: getSamplePermalink( state ), + samplePermalink: getPermalink( state ), }; } )( PostPermalink ); diff --git a/editor/store/selectors.js b/editor/store/selectors.js index b0cc2987ba2977..4d68ea9be0aaff 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -31,6 +31,7 @@ import { deprecated } from '@wordpress/utils'; */ const MAX_RECENT_BLOCKS = 9; export const POST_UPDATE_TRANSACTION_ID = 'post-update'; +const PERMALINK_POSTNAME_REGEX = /%(?:postname|pagename)%/; /** * Shared reference to an empty array for cases where it is important to avoid @@ -1525,20 +1526,41 @@ export function getProvisionalBlockUID( state ) { * @return {boolean} Whether or not the permalink is editable. */ export function isPermalinkEditable( state ) { - const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); + const permalinkTemplate = getEditedPostAttribute( state, 'permalink_template' ); - return /%(?:postname|pagename)%/.test( samplePermalinkData[ 0 ] ); + return PERMALINK_POSTNAME_REGEX.test( permalinkTemplate ); } /** - * Returns the sample permalink for the post. + * Returns the permalink for the post. * * @param {Object} state Editor state. * - * @return {string} The sample permalink. + * @return {string} The permalink. */ -export function getSamplePermalink( state ) { - const samplePermalinkData = getEditedPostAttribute( state, 'sample_permalink' ); +export function getPermalink( state ) { + const {prefix, postName, suffix } = getPermalinkParts( state ); + return prefix + postName + suffix; - return samplePermalinkData[ 0 ].replace( /%(?:postname|pagename)%/, samplePermalinkData[ 1 ] ); + return permalinkParts.values().join( '' ); +} + +/** + * Returns the permalink for a post, split into it's three parts: the prefix, the postName, and the suffix. + * + * @param {Object} state Editor state. + * + * @return {Object} The prefix, postName, and suffix for the permalink. + */ +export function getPermalinkParts( state ) { + const permalinkTemplate = getEditedPostAttribute( state, 'permalink_template' ); + const postName = getEditedPostAttribute( state, 'slug' ); + + const [ prefix, suffix ] = permalinkTemplate.split( PERMALINK_POSTNAME_REGEX ); + + return { + prefix, + postName, + suffix, + }; } diff --git a/lib/compat.php b/lib/compat.php index 49edbab66e7367..63c3a667dd7496 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -439,12 +439,12 @@ function gutenberg_get_taxonomy_visibility_data( $object ) { add_action( 'rest_api_init', 'gutenberg_add_taxonomy_visibility_field' ); /** - * Add a sample permalink to draft posts in the post REST API response. + * Add a permalink template to posts in the post REST API response. * * @param WP_REST_Response $response WP REST API response of a post. * @param WP_Post $post The post being returned. * @param WP_REST_Request $request WP REST API request. - * @return WP_REST_Response Response containing the sample_permalink. + * @return WP_REST_Response Response containing the permalink_template. */ function gutenberg_add_sample_permalink_to_posts( $response, $post, $request ) { if ( 'edit' !== $request['context'] ) { @@ -455,7 +455,8 @@ function gutenberg_add_sample_permalink_to_posts( $response, $post, $request ) { require_once ABSPATH . '/wp-admin/includes/post.php'; } - $response->data['sample_permalink'] = get_sample_permalink( $post->ID ); + $sample_permalink = get_sample_permalink( $post->ID ); + $response->data['permalink_template'] = $sample_permalink[0]; return $response; } /** From 19f4f3afb1a554d59c8fc06a47616511386da08a Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 15:22:51 +1000 Subject: [PATCH 44/63] Fix Travis --- editor/store/selectors.js | 4 +--- lib/compat.php | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/editor/store/selectors.js b/editor/store/selectors.js index 4d68ea9be0aaff..05ebf8c0d86ad4 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1539,10 +1539,8 @@ export function isPermalinkEditable( state ) { * @return {string} The permalink. */ export function getPermalink( state ) { - const {prefix, postName, suffix } = getPermalinkParts( state ); + const { prefix, postName, suffix } = getPermalinkParts( state ); return prefix + postName + suffix; - - return permalinkParts.values().join( '' ); } /** diff --git a/lib/compat.php b/lib/compat.php index 63c3a667dd7496..e35bf411cac9dd 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -446,7 +446,7 @@ function gutenberg_get_taxonomy_visibility_data( $object ) { * @param WP_REST_Request $request WP REST API request. * @return WP_REST_Response Response containing the permalink_template. */ -function gutenberg_add_sample_permalink_to_posts( $response, $post, $request ) { +function gutenberg_add_permalink_template_to_posts( $response, $post, $request ) { if ( 'edit' !== $request['context'] ) { return $response; } @@ -459,17 +459,18 @@ function gutenberg_add_sample_permalink_to_posts( $response, $post, $request ) { $response->data['permalink_template'] = $sample_permalink[0]; return $response; } + /** * Whenever a post type is registered, ensure we're hooked into it's WP REST API response. * * @param string $post_type The newly registered post type. * @return string That same post type. */ -function gutenberg_register_sample_permalink_function( $post_type ) { - add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_sample_permalink_to_posts', 10, 3 ); +function gutenberg_register_permalink_template_function( $post_type ) { + add_filter( "rest_prepare_{$post_type}", 'gutenberg_add_permalink_template_to_posts', 10, 3 ); return $post_type; } -add_filter( 'registered_post_type', 'gutenberg_register_sample_permalink_function' ); +add_filter( 'registered_post_type', 'gutenberg_register_permalink_template_function' ); /** * Add an is_viewable flag to the posttype REST API response. From aeb3a841f1ff7ffe282561e799c5ba95f7eacc5d Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 16:15:01 +1000 Subject: [PATCH 45/63] Reset the local copy of the postname, if the server has returned a santised version. --- editor/store/effects.js | 11 ++++++++++- editor/store/reducer.js | 9 +++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/editor/store/effects.js b/editor/store/effects.js index bf40697c05d5d7..6ef1e1ad0a2795 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -117,6 +117,7 @@ export default { type: 'REQUEST_POST_UPDATE_SUCCESS', previousPost: post, post: newPost, + edits: toSend, optimist: { type: COMMIT, id: POST_UPDATE_TRANSACTION_ID }, } ); }, @@ -135,7 +136,7 @@ export default { ); }, REQUEST_POST_UPDATE_SUCCESS( action, store ) { - const { previousPost, post } = action; + const { previousPost, post, edits } = action; const { dispatch } = store; const publishStatus = [ 'publish', 'private', 'future' ]; @@ -175,6 +176,14 @@ export default { ) ); } + // The server can return a sanitised version of the slug, + // in which case we need to update our local copy. + if ( edits.slug !== post.slug ) { + dispatch( { + type: 'POSTNAME_SANITIZED', + } ); + } + if ( get( window.history.state, 'id' ) !== post.id ) { window.history.replaceState( { id: post.id }, diff --git a/editor/store/reducer.js b/editor/store/reducer.js index d36fbc32fe7494..263df4b87f2ef0 100644 --- a/editor/store/reducer.js +++ b/editor/store/reducer.js @@ -217,7 +217,7 @@ export const editor = flow( [ // Track undo history, starting at editor initialization. withHistory( { resetTypes: [ 'SETUP_EDITOR_STATE' ], - ignoreTypes: [ 'RECEIVE_BLOCKS' ], + ignoreTypes: [ 'RECEIVE_BLOCKS', 'POSTNAME_SANITIZED' ], shouldOverwriteState, } ), @@ -225,7 +225,7 @@ export const editor = flow( [ // editor initialization firing post reset as an effect. withChangeDetection( { resetTypes: [ 'SETUP_EDITOR_STATE', 'RESET_POST' ], - ignoreTypes: [ 'RECEIVE_BLOCKS' ], + ignoreTypes: [ 'RECEIVE_BLOCKS', 'POSTNAME_SANITIZED' ], } ), ] )( { edits( state = {}, action ) { @@ -267,6 +267,11 @@ export const editor = flow( [ delete result[ key ]; return result; }, state ); + + case 'POSTNAME_SANITIZED': + if ( 'slug' in state ) { + return omit( state, 'slug' ); + } } return state; From 14d23ee51325f371f3359bcce398d45e59debc30 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 16:16:06 +1000 Subject: [PATCH 46/63] Actually fix Travis. --- lib/compat.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/compat.php b/lib/compat.php index e35bf411cac9dd..7a8502a7805e8f 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -456,7 +456,9 @@ function gutenberg_add_permalink_template_to_posts( $response, $post, $request ) } $sample_permalink = get_sample_permalink( $post->ID ); + $response->data['permalink_template'] = $sample_permalink[0]; + return $response; } From 38e5444cab8f17217c40c321dde3af37403fb3cb Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 11 Apr 2018 16:25:27 +1000 Subject: [PATCH 47/63] =?UTF-8?q?=F0=9F=92=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- editor/store/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/store/effects.js b/editor/store/effects.js index 6ef1e1ad0a2795..2be08fb28172db 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -178,7 +178,7 @@ export default { // The server can return a sanitised version of the slug, // in which case we need to update our local copy. - if ( edits.slug !== post.slug ) { + if ( get( edits, 'slug' ) !== post.slug ) { dispatch( { type: 'POSTNAME_SANITIZED', } ); From 380f40eeb865821d9584cd171f9b2cc3d6ca8770 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 15:27:43 +1000 Subject: [PATCH 48/63] Allow the postname field to be cleared. --- editor/components/post-permalink/editor.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/editor/components/post-permalink/editor.js b/editor/components/post-permalink/editor.js index 10a17f90f36dfb..64a5a2f87a9fd9 100644 --- a/editor/components/post-permalink/editor.js +++ b/editor/components/post-permalink/editor.js @@ -12,11 +12,11 @@ import { Button } from '@wordpress/components'; import './style.scss'; class PostPermalinkEditor extends Component { - constructor() { + constructor( { permalinkParts } ) { super( ...arguments ); this.state = { - editedPostName: '', + editedPostName: permalinkParts.postName, }; this.onSavePermalink = this.onSavePermalink.bind( this ); @@ -43,12 +43,8 @@ class PostPermalinkEditor extends Component { } render() { - const { - prefix, - suffix, - postName, - } = this.props.permalinkParts; - const editedPostName = this.state.editedPostName || postName; + const { prefix, suffix } = this.props.permalinkParts; + const { editedPostName } = this.state; /* eslint-disable jsx-a11y/no-autofocus */ // Autofocus is allowed here, as this mini-UI is only loaded when the user clicks to open it. From 98c36f78f63971c42c1eaea810f9c370c1a67998 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 15:28:20 +1000 Subject: [PATCH 49/63] Button: remove an unnecessary bind(). --- components/button/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/components/button/index.js b/components/button/index.js index 0ac86f6051f33d..49713d398a8245 100644 --- a/components/button/index.js +++ b/components/button/index.js @@ -17,7 +17,6 @@ class Button extends Component { constructor( props ) { super( props ); this.setRef = this.setRef.bind( this ); - this.focus = this.focus.bind( this ); } componentDidMount() { From f63debc2016c7958a4d628e41adc9f00ce90e7d0 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 15:46:55 +1000 Subject: [PATCH 50/63] Rename editingPermalink to isEditingPermalink. --- editor/components/post-permalink/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index fbe96058b7c9d3..07f0d4d35bc912 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -24,20 +24,20 @@ class PostPermalink extends Component { this.state = { iconClass: '', - editingPermalink: false, + isEditingPermalink: false, }; } componentDidUpdate( prevProps, prevState ) { // If we've just stopped editing the permalink, focus on the new permalink. - if ( prevState.editingPermalink && ! this.state.editingPermalink ) { + if ( prevState.isEditingPermalink && ! this.state.isEditingPermalink ) { this.permalinkButton.focus(); } } render() { const { isNew, previewLink, isEditable, samplePermalink } = this.props; - const { iconClass, editingPermalink } = this.state; + const { iconClass, isEditingPermalink } = this.state; if ( isNew || ! previewLink ) { return null; @@ -57,7 +57,7 @@ class PostPermalink extends Component { { __( 'Permalink:' ) } - { ! editingPermalink && + { ! isEditingPermalink && From daa4b8f9bd1f6a14130cfce837be3f2b2bc7ce05 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 15:52:30 +1000 Subject: [PATCH 51/63] Nudge the copy button a little. --- editor/components/post-permalink/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/editor/components/post-permalink/style.scss b/editor/components/post-permalink/style.scss index 23fb7446e89bde..1747133f5b8966 100644 --- a/editor/components/post-permalink/style.scss +++ b/editor/components/post-permalink/style.scss @@ -17,6 +17,10 @@ } } +.editor-post-permalink__copy { + margin-top: 4px; +} + .editor-post-permalink__copy .is-copied { opacity: 0.3; } From 1f703b05d4d972f0248eca118d17c3eed6297138 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 20:49:19 +1000 Subject: [PATCH 52/63] Refresh the post when the user returns to the page after having clicked the Change Permalinks button. --- editor/components/post-permalink/index.js | 42 +++++++++++++++-------- editor/store/actions.js | 6 ++++ editor/store/effects.js | 17 +++++++++ editor/store/selectors.js | 7 +++- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 07f0d4d35bc912..c1498ad921b3a0 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -1,12 +1,8 @@ -/** - * External dependencies - */ -import { connect } from 'react-redux'; - /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; +import { withDispatch, withSelect } from '@wordpress/data'; +import { Component, compose } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Dashicon, Button, ClipboardButton, Tooltip } from '@wordpress/components'; @@ -15,19 +11,29 @@ import { Dashicon, Button, ClipboardButton, Tooltip } from '@wordpress/component */ import './style.scss'; import PostPermalinkEditor from './editor.js'; -import { isEditedPostNew, isPermalinkEditable, getEditedPostPreviewLink, getPermalink } from '../../store/selectors'; import { getWPAdminURL } from '../../utils/url'; class PostPermalink extends Component { constructor() { super( ...arguments ); + this.onVisibilityChange = this.onVisibilityChange.bind( this ); + this.state = { iconClass: '', isEditingPermalink: false, }; } + onVisibilityChange( event ) { + const { isEditable, refreshPost } = this.props; + // If the user just returned after having clicked the "Change Permalinks" button, + // fetch a new copy of the post from the server, just in case they enabled permalinks. + if ( ! isEditable && 'visible' === document.visibilityState ) { + refreshPost(); + } + } + componentDidUpdate( prevProps, prevState ) { // If we've just stopped editing the permalink, focus on the new permalink. if ( prevState.isEditingPermalink && ! this.state.isEditingPermalink ) { @@ -90,6 +96,7 @@ class PostPermalink extends Component { className="editor-post-permalink__change" isLarge href={ getWPAdminURL( 'options-permalink.php' ) } + onClick={ window.addEventListener( 'visibilitychange', this.onVisibilityChange ) } target="_blank" > { __( 'Change Permalinks' ) } @@ -100,14 +107,19 @@ class PostPermalink extends Component { } } -export default connect( - ( state ) => { +export default compose( [ + withSelect( ( select ) => { + const { isEditedPostNew, isPermalinkEditable, getEditedPostPreviewLink, getPermalink } = select( 'core/editor' ); return { - isNew: isEditedPostNew( state ), - previewLink: getEditedPostPreviewLink( state ), - isEditable: isPermalinkEditable( state ), - samplePermalink: getPermalink( state ), + isNew: isEditedPostNew(), + previewLink: getEditedPostPreviewLink(), + isEditable: isPermalinkEditable(), + samplePermalink: getPermalink(), }; - } -)( PostPermalink ); + } ), + withDispatch( ( dispatch ) => { + const { refreshPost } = dispatch( 'core/editor' ); + return { refreshPost }; + } ), +] )( PostPermalink ); diff --git a/editor/store/actions.js b/editor/store/actions.js index e05824b9c851e8..b0291859245836 100644 --- a/editor/store/actions.js +++ b/editor/store/actions.js @@ -337,6 +337,12 @@ export function savePost() { }; } +export function refreshPost() { + return { + type: 'UPDATE_POST_FROM_SERVER', + } +} + export function trashPost( postId, postType ) { return { type: 'TRASH_POST', diff --git a/editor/store/effects.js b/editor/store/effects.js index 2be08fb28172db..7193bd5c0c4bdd 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -247,6 +247,23 @@ export default { const message = action.error.message && action.error.code !== 'unknown_error' ? action.error.message : __( 'Trashing failed' ); store.dispatch( createErrorNotice( message, { id: TRASH_POST_NOTICE_ID } ) ); }, + UPDATE_POST_FROM_SERVER( action, store ) { + const { dispatch, getState } = store; + + const state = getState(); + const post = getCurrentPost( state ); + const basePath = wp.api.getPostTypeRoute( getCurrentPostType( state ) ); + + const data = { + context: 'edit', + }; + + wp.apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, method: 'GET', data } ).then( + ( newPost ) => { + dispatch( resetPost( newPost ) ); + } + ); + }, MERGE_BLOCKS( action, store ) { const { dispatch } = store; const state = store.getState(); diff --git a/editor/store/selectors.js b/editor/store/selectors.js index 05ebf8c0d86ad4..4d078a0d0cfd6b 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1540,7 +1540,12 @@ export function isPermalinkEditable( state ) { */ export function getPermalink( state ) { const { prefix, postName, suffix } = getPermalinkParts( state ); - return prefix + postName + suffix; + + if ( isPermalinkEditable( state ) ) { + return prefix + postName + suffix; + } else { + return prefix; + } } /** From 40eff873cb9bc80952472882979d01b0e62f15a4 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 22:05:47 +1000 Subject: [PATCH 53/63] Add tests for the permalink selectors. --- editor/store/test/selectors.js | 92 ++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/editor/store/test/selectors.js b/editor/store/test/selectors.js index e89c0f445f0ab2..a3c6d7e1ca3209 100644 --- a/editor/store/test/selectors.js +++ b/editor/store/test/selectors.js @@ -84,6 +84,9 @@ const { getTemplate, getTemplateLock, POST_UPDATE_TRANSACTION_ID, + isPermalinkEditable, + getPermalink, + getPermalinkParts, } = selectors; describe( 'selectors', () => { @@ -3093,4 +3096,93 @@ describe( 'selectors', () => { expect( getTemplateLock( state ) ).toBe( 'all' ); } ); } ); + + describe( 'isPermalinkEditable', () => { + it( 'should be false if there is no permalink', () => { + const state = { + currentPost: { permalink_template: '' }, + }; + + expect( isPermalinkEditable( state ) ).toBe( false ); + } ); + + it( 'should be false if the permalink is not of an editable kind', () => { + const state = { + currentPost: { permalink_template: 'http://foo.test/bar/%baz%/' }, + }; + + expect( isPermalinkEditable( state ) ).toBe( false ); + } ); + + it( 'should be true if the permalink has %postname%', () => { + const state = { + currentPost: { permalink_template: 'http://foo.test/bar/%postname%/' }, + }; + + expect( isPermalinkEditable( state ) ).toBe( true ); + } ); + + it( 'should be true if the permalink has %pagename%', () => { + const state = { + currentPost: { permalink_template: 'http://foo.test/bar/%pagename%/' }, + }; + + expect( isPermalinkEditable( state ) ).toBe( true ); + } ); + } ); + + describe( 'getPermalink', () => { + it( 'should work if the permalink is not of an editable kind', () => { + const url = 'http://foo.test/?post=1'; + const state = { + currentPost: { permalink_template: url }, + }; + + expect( getPermalink( state ) ).toBe( url ); + } ); + + it( 'should return the permalink if it is editable', () => { + const state = { + currentPost: { + permalink_template: 'http://foo.test/bar/%postname%/', + slug: 'baz', + }, + }; + + expect( getPermalink( state ) ).toBe( 'http://foo.test/bar/baz/' ); + } ); + } ); + + describe( 'getPermalinkParts', () => { + it( 'should split the permalink correctly', () => { + const parts = { + prefix: 'http://foo.test/bar/', + postName: 'baz', + suffix: '/', + }; + const state = { + currentPost: { + permalink_template: 'http://foo.test/bar/%postname%/', + slug: 'baz', + }, + }; + + expect( getPermalinkParts( state ) ).toEqual( parts ); + } ); + + it( 'should leave an uneditable permalink in the prefix', () => { + const parts = { + prefix: 'http://foo.test/?post=1', + postName: 'baz', + }; + const state = { + currentPost: { + permalink_template: 'http://foo.test/?post=1', + slug: 'baz', + }, + }; + + expect( getPermalinkParts( state ) ).toEqual( parts ); + } ); + } ); } ); From 0bf43deb665fdfbecce8c1a5fd54b219f30e0c51 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 22:25:43 +1000 Subject: [PATCH 54/63] Use getPostType() for getting the post type. --- editor/components/post-title/index.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/editor/components/post-title/index.js b/editor/components/post-title/index.js index 3b876a34f71718..6a194901fb5377 100644 --- a/editor/components/post-title/index.js +++ b/editor/components/post-title/index.js @@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n'; import { Component, compose } from '@wordpress/element'; import { keycodes, decodeEntities } from '@wordpress/utils'; import { withSelect, withDispatch } from '@wordpress/data'; -import { KeyboardShortcuts, withContext, withInstanceId, withFocusOutside, withAPIData } from '@wordpress/components'; +import { KeyboardShortcuts, withContext, withInstanceId, withFocusOutside } from '@wordpress/components'; /** * Internal dependencies @@ -92,7 +92,7 @@ class PostTitle extends Component { const { isSelected } = this.state; const className = classnames( 'editor-post-title', { 'is-selected': isSelected } ); const decodedPlaceholder = decodeEntities( placeholder ); - const isPostTypeViewable = get( postType, 'data.is_viewable', false ); + const isPostTypeViewable = get( postType, 'is_viewable', false ); return ( @@ -125,19 +125,12 @@ class PostTitle extends Component { } const applyWithSelect = withSelect( ( select ) => { - const { getEditedPostAttribute, getCurrentPostType } = select( 'core/editor' ); + const { getEditedPostAttribute } = select( 'core/editor' ); + const { getPostType } = select( 'core' ); return { title: getEditedPostAttribute( 'title' ), - postTypeSlug: getCurrentPostType(), - }; -} ); - -const applyWithAPIData = withAPIData( ( props ) => { - const { postTypeSlug } = props; - - return { - postType: `/wp/v2/types/${ postTypeSlug }?context=edit`, + postType: getPostType( getEditedPostAttribute( 'type' ) ), }; } ); @@ -171,7 +164,6 @@ const applyEditorSettings = withContext( 'editor' )( export default compose( applyWithSelect, - applyWithAPIData, applyWithDispatch, applyEditorSettings, withInstanceId, From 5db2b58497b8215f86f2c46d964f81f4d8ae3431 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Thu, 12 Apr 2018 22:28:34 +1000 Subject: [PATCH 55/63] Fix some linting errors. --- editor/components/post-permalink/index.js | 2 +- editor/store/actions.js | 2 +- editor/store/selectors.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index c1498ad921b3a0..008de679997b0f 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -25,7 +25,7 @@ class PostPermalink extends Component { }; } - onVisibilityChange( event ) { + onVisibilityChange() { const { isEditable, refreshPost } = this.props; // If the user just returned after having clicked the "Change Permalinks" button, // fetch a new copy of the post from the server, just in case they enabled permalinks. diff --git a/editor/store/actions.js b/editor/store/actions.js index b0291859245836..17d5bee173c5df 100644 --- a/editor/store/actions.js +++ b/editor/store/actions.js @@ -340,7 +340,7 @@ export function savePost() { export function refreshPost() { return { type: 'UPDATE_POST_FROM_SERVER', - } + }; } export function trashPost( postId, postType ) { diff --git a/editor/store/selectors.js b/editor/store/selectors.js index 4d078a0d0cfd6b..5307c91468420e 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1543,9 +1543,9 @@ export function getPermalink( state ) { if ( isPermalinkEditable( state ) ) { return prefix + postName + suffix; - } else { - return prefix; } + + return prefix; } /** From 6ded524ec2f1eabfe0da6e8a2df93753170c6145 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 13:59:09 +1000 Subject: [PATCH 56/63] Move the addEventListener to a callback, and remove it when the component is unmounting. --- editor/components/post-permalink/index.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/editor/components/post-permalink/index.js b/editor/components/post-permalink/index.js index 008de679997b0f..b479e7aac288f0 100644 --- a/editor/components/post-permalink/index.js +++ b/editor/components/post-permalink/index.js @@ -17,6 +17,7 @@ class PostPermalink extends Component { constructor() { super( ...arguments ); + this.addVisibilityCheck = this.addVisibilityCheck.bind( this ); this.onVisibilityChange = this.onVisibilityChange.bind( this ); this.state = { @@ -25,6 +26,10 @@ class PostPermalink extends Component { }; } + addVisibilityCheck() { + window.addEventListener( 'visibilitychange', this.onVisibilityChange ); + } + onVisibilityChange() { const { isEditable, refreshPost } = this.props; // If the user just returned after having clicked the "Change Permalinks" button, @@ -41,6 +46,10 @@ class PostPermalink extends Component { } } + componentWillUnmount() { + window.removeEventListener( 'visibilitychange', this.addVisibilityCheck ); + } + render() { const { isNew, previewLink, isEditable, samplePermalink } = this.props; const { iconClass, isEditingPermalink } = this.state; @@ -96,7 +105,7 @@ class PostPermalink extends Component { className="editor-post-permalink__change" isLarge href={ getWPAdminURL( 'options-permalink.php' ) } - onClick={ window.addEventListener( 'visibilitychange', this.onVisibilityChange ) } + onClick={ this.addVisibilityCheck } target="_blank" > { __( 'Change Permalinks' ) } From fb49a35bf277d60d0b0d69f8db6fd312604a3a66 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 14:01:50 +1000 Subject: [PATCH 57/63] Rename UPDATE_POST_FROM_SERVER to REFRESH_POST --- editor/store/actions.js | 2 +- editor/store/effects.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/store/actions.js b/editor/store/actions.js index 17d5bee173c5df..4a3ce8a6a356d1 100644 --- a/editor/store/actions.js +++ b/editor/store/actions.js @@ -339,7 +339,7 @@ export function savePost() { export function refreshPost() { return { - type: 'UPDATE_POST_FROM_SERVER', + type: 'REFRESH_POST', }; } diff --git a/editor/store/effects.js b/editor/store/effects.js index 7193bd5c0c4bdd..65cd2acd4caddb 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -247,7 +247,7 @@ export default { const message = action.error.message && action.error.code !== 'unknown_error' ? action.error.message : __( 'Trashing failed' ); store.dispatch( createErrorNotice( message, { id: TRASH_POST_NOTICE_ID } ) ); }, - UPDATE_POST_FROM_SERVER( action, store ) { + REFRESH_POST( action, store ) { const { dispatch, getState } = store; const state = getState(); From 91e26fbe2a7f9f145d575f2b34c42ff2329fee40 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 14:03:40 +1000 Subject: [PATCH 58/63] Performance improvement of a get() call. --- editor/store/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/store/effects.js b/editor/store/effects.js index 65cd2acd4caddb..57536026b75871 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -178,7 +178,7 @@ export default { // The server can return a sanitised version of the slug, // in which case we need to update our local copy. - if ( get( edits, 'slug' ) !== post.slug ) { + if ( get( edits, [ 'slug' ] ) !== post.slug ) { dispatch( { type: 'POSTNAME_SANITIZED', } ); From 17392bd833765e8e06d5be80f463b1800ebc0d34 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 14:13:38 +1000 Subject: [PATCH 59/63] Remove POSTNAME_SANITIZED, handle it in UPDATE_POST --- editor/store/effects.js | 10 +--------- editor/store/reducer.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/editor/store/effects.js b/editor/store/effects.js index 57536026b75871..c6c687a315ddd5 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -136,7 +136,7 @@ export default { ); }, REQUEST_POST_UPDATE_SUCCESS( action, store ) { - const { previousPost, post, edits } = action; + const { previousPost, post } = action; const { dispatch } = store; const publishStatus = [ 'publish', 'private', 'future' ]; @@ -176,14 +176,6 @@ export default { ) ); } - // The server can return a sanitised version of the slug, - // in which case we need to update our local copy. - if ( get( edits, [ 'slug' ] ) !== post.slug ) { - dispatch( { - type: 'POSTNAME_SANITIZED', - } ); - } - if ( get( window.history.state, 'id' ) !== post.id ) { window.history.replaceState( { id: post.id }, diff --git a/editor/store/reducer.js b/editor/store/reducer.js index 263df4b87f2ef0..6d981f278de586 100644 --- a/editor/store/reducer.js +++ b/editor/store/reducer.js @@ -217,7 +217,7 @@ export const editor = flow( [ // Track undo history, starting at editor initialization. withHistory( { resetTypes: [ 'SETUP_EDITOR_STATE' ], - ignoreTypes: [ 'RECEIVE_BLOCKS', 'POSTNAME_SANITIZED' ], + ignoreTypes: [ 'RECEIVE_BLOCKS' ], shouldOverwriteState, } ), @@ -225,7 +225,7 @@ export const editor = flow( [ // editor initialization firing post reset as an effect. withChangeDetection( { resetTypes: [ 'SETUP_EDITOR_STATE', 'RESET_POST' ], - ignoreTypes: [ 'RECEIVE_BLOCKS', 'POSTNAME_SANITIZED' ], + ignoreTypes: [ 'RECEIVE_BLOCKS' ], } ), ] )( { edits( state = {}, action ) { @@ -254,9 +254,14 @@ export const editor = flow( [ return state; + case 'UPDATE_POST': case 'RESET_POST': + const getCanonicalValue = action.type === 'UPDATE_POST' ? + ( key ) => action.edits[ key ] : + ( key ) => getPostRawValue( action.post[ key ] ); + return reduce( state, ( result, value, key ) => { - if ( value !== getPostRawValue( action.post[ key ] ) ) { + if ( value !== getCanonicalValue( key ) ) { return result; } @@ -267,11 +272,6 @@ export const editor = flow( [ delete result[ key ]; return result; }, state ); - - case 'POSTNAME_SANITIZED': - if ( 'slug' in state ) { - return omit( state, 'slug' ); - } } return state; From 48fbdec3bc18751586cb4a9946d6590db0544912 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 14:14:42 +1000 Subject: [PATCH 60/63] Remove the GET method from the post refresh request, as that's the default. --- editor/store/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/store/effects.js b/editor/store/effects.js index c6c687a315ddd5..cf8ac1774354b8 100644 --- a/editor/store/effects.js +++ b/editor/store/effects.js @@ -250,7 +250,7 @@ export default { context: 'edit', }; - wp.apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, method: 'GET', data } ).then( + wp.apiRequest( { path: `/wp/v2/${ basePath }/${ post.id }`, data } ).then( ( newPost ) => { dispatch( resetPost( newPost ) ); } From 8766dab745e25650f151f2254868934a4141ccd8 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 15:34:00 +1000 Subject: [PATCH 61/63] Rename the posttype is_viewable flag to viewable. --- editor/components/post-title/index.js | 6 ++--- lib/compat.php | 37 ++++++++++++++++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/editor/components/post-title/index.js b/editor/components/post-title/index.js index 6a194901fb5377..10245c8b5f6872 100644 --- a/editor/components/post-title/index.js +++ b/editor/components/post-title/index.js @@ -88,11 +88,10 @@ class PostTitle extends Component { } render() { - const { title, placeholder, instanceId, postType } = this.props; + const { title, placeholder, instanceId, isPostTypeViewable } = this.props; const { isSelected } = this.state; const className = classnames( 'editor-post-title', { 'is-selected': isSelected } ); const decodedPlaceholder = decodeEntities( placeholder ); - const isPostTypeViewable = get( postType, 'is_viewable', false ); return ( @@ -127,10 +126,11 @@ class PostTitle extends Component { const applyWithSelect = withSelect( ( select ) => { const { getEditedPostAttribute } = select( 'core/editor' ); const { getPostType } = select( 'core' ); + const postType = getPostType( getEditedPostAttribute( 'type' ) ) return { title: getEditedPostAttribute( 'title' ), - postType: getPostType( getEditedPostAttribute( 'type' ) ), + isPostTypeViewable: get( postType, [ 'viewable' ], false ), }; } ); diff --git a/lib/compat.php b/lib/compat.php index 7a8502a7805e8f..ec70d93ba5f60b 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -475,15 +475,34 @@ function gutenberg_register_permalink_template_function( $post_type ) { add_filter( 'registered_post_type', 'gutenberg_register_permalink_template_function' ); /** - * Add an is_viewable flag to the posttype REST API response. + * Includes the value for the 'viewable' attribute of a post type resource. * - * @param WP_REST_Response $response WP REST API response of a post. - * @param WP_Post_Type $post_type The post_type being returned. - * @param WP_REST_Request $request WP REST API request. - * @return WP_REST_Response Response containing is_viewable flag. + * @see https://core.trac.wordpress.org/ticket/43739 + * + * @param object $post_type Post type response object. + * @return boolean Whether or not the post type can be viewed. */ -function gutenberg_add_viewable_flag_to_post_types( $response, $post_type, $request ) { - $response->data['is_viewable'] = is_post_type_viewable( $post_type ); - return $response; +function gutenberg_get_post_type_viewable( $post_type ) { + return is_post_type_viewable( $post_type['slug'] ); +} + +/** + * Adds the 'viewable' attribute to the REST API response of a post type. + * + * @see https://core.trac.wordpress.org/ticket/43739 + */ +function gutenberg_register_rest_api_post_type_viewable() { + register_rest_field( 'type', + 'viewable', + array( + 'get_callback' => 'gutenberg_get_post_type_viewable', + 'schema' => array( + 'description' => __( 'Whether or not the post type can be viewed', 'gutenberg' ), + 'type' => 'boolean', + 'context' => array( 'edit' ), + 'readonly' => true, + ), + ) + ); } -add_filter( 'rest_prepare_post_type', 'gutenberg_add_viewable_flag_to_post_types', 10, 3 ); +add_action( 'rest_api_init', 'gutenberg_register_rest_api_post_type_viewable' ); From 7e561483e666e392ca7d56acdf4d1004aa81758c Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 15:37:12 +1000 Subject: [PATCH 62/63] Add a draft_slug to the REST API response for posts that are drafts, and don't have a slug defined. --- editor/store/selectors.js | 2 +- lib/compat.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/editor/store/selectors.js b/editor/store/selectors.js index 5307c91468420e..9bbe5e78b15947 100644 --- a/editor/store/selectors.js +++ b/editor/store/selectors.js @@ -1557,7 +1557,7 @@ export function getPermalink( state ) { */ export function getPermalinkParts( state ) { const permalinkTemplate = getEditedPostAttribute( state, 'permalink_template' ); - const postName = getEditedPostAttribute( state, 'slug' ); + const postName = getEditedPostAttribute( state, 'slug' ) || getEditedPostAttribute( state, 'draft_slug' ); const [ prefix, suffix ] = permalinkTemplate.split( PERMALINK_POSTNAME_REGEX ); diff --git a/lib/compat.php b/lib/compat.php index ec70d93ba5f60b..23ceedb0f011b6 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -459,6 +459,10 @@ function gutenberg_add_permalink_template_to_posts( $response, $post, $request ) $response->data['permalink_template'] = $sample_permalink[0]; + if ( 'draft' === $post->post_status && ! $post->post_name ) { + $response->data['draft_slug'] = $sample_permalink[1]; + } + return $response; } From 6d3960f0a54815158a74eaaf0ac2b2695fb31594 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 13 Apr 2018 15:42:37 +1000 Subject: [PATCH 63/63] Linting. --- editor/components/post-title/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/components/post-title/index.js b/editor/components/post-title/index.js index 10245c8b5f6872..2fc71fe818ed8e 100644 --- a/editor/components/post-title/index.js +++ b/editor/components/post-title/index.js @@ -126,7 +126,7 @@ class PostTitle extends Component { const applyWithSelect = withSelect( ( select ) => { const { getEditedPostAttribute } = select( 'core/editor' ); const { getPostType } = select( 'core' ); - const postType = getPostType( getEditedPostAttribute( 'type' ) ) + const postType = getPostType( getEditedPostAttribute( 'type' ) ); return { title: getEditedPostAttribute( 'title' ),