Skip to content

Commit

Permalink
Add logic for basic (temporary) wp_template editing UI (#17625)
Browse files Browse the repository at this point in the history
* Templates: Add logic for basic temporary editing UI.

* Templates: Fix menu filter.

* Post Slug: Follow class name convention.
  • Loading branch information
felixarntz authored and epiqueras committed Oct 23, 2019
1 parent 53eca43 commit 6cf43ac
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 10 deletions.
93 changes: 83 additions & 10 deletions lib/templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,42 @@ function gutenberg_register_template_post_type() {
}

$labels = array(
'name' => __( 'Templates', 'gutenberg' ),
'name' => __( 'Templates', 'gutenberg' ),
'singular_name' => __( 'Template', 'gutenberg' ),
'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ),
'add_new' => _x( 'Add New', 'Template', 'gutenberg' ),
'add_new_item' => __( 'Add New Template', 'gutenberg' ),
'new_item' => __( 'New Template', 'gutenberg' ),
'edit_item' => __( 'Edit Template', 'gutenberg' ),
'view_item' => __( 'View Template', 'gutenberg' ),
'all_items' => __( 'All Templates', 'gutenberg' ),
'search_items' => __( 'Search Templates', 'gutenberg' ),
'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ),
'not_found' => __( 'No templates found.', 'gutenberg' ),
'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ),
'archives' => __( 'Template archives', 'gutenberg' ),
'insert_into_item' => __( 'Insert into template', 'gutenberg' ),
'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ),
'filter_items_list' => __( 'Filter templates list', 'gutenberg' ),
'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ),
'items_list' => __( 'Templates list', 'gutenberg' ),
);

$args = array(
'labels' => $labels,
'description' => __( 'Templates to include in your theme.', 'gutenberg' ),
'public' => false,
'has_archive' => false,
'show_in_rest' => true,
'rest_base' => 'templates',
'capability_type' => array( 'template', 'templates' ),
'map_meta_cap' => true,
'supports' => array(
'labels' => $labels,
'description' => __( 'Templates to include in your theme.', 'gutenberg' ),
'public' => false,
'has_archive' => false,
'show_ui' => true,
'show_in_menu' => 'themes.php',
'show_in_admin_bar' => false,
'show_in_rest' => true,
'rest_base' => 'templates',
'capability_type' => array( 'template', 'templates' ),
'map_meta_cap' => true,
'supports' => array(
'title',
'slug',
'editor',
'revisions',
),
Expand Down Expand Up @@ -94,3 +116,54 @@ function gutenberg_prevent_index_template_deletion( $caps, $cap, $user_id, $args
return $caps;
}
add_filter( 'map_meta_cap', 'gutenberg_prevent_index_template_deletion', 10, 4 );

/**
* Fixes the label of the 'wp_template' admin menu entry.
*/
function gutenberg_fix_template_admin_menu_entry() {
global $submenu;
if ( ! isset( $submenu['themes.php'] ) ) {
return;
}
$post_type = get_post_type_object( 'wp_template' );
if ( ! $post_type ) {
return;
}
foreach ( $submenu['themes.php'] as $key => $submenu_entry ) {
if ( $post_type->labels->all_items === $submenu['themes.php'][ $key ][0] ) {
$submenu['themes.php'][ $key ][0] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride
break;
}
}
}
add_action( 'admin_menu', 'gutenberg_fix_template_admin_menu_entry' );

/**
* Filters the 'wp_template' post type columns in the admin list table.
*
* @param array $columns Columns to display.
* @return array Filtered $columns.
*/
function gutenberg_filter_template_list_table_columns( array $columns ) {
$columns['slug'] = __( 'Slug', 'gutenberg' );
if ( isset( $columns['date'] ) ) {
unset( $columns['date'] );
}
return $columns;
}
add_filter( 'manage_wp_template_posts_columns', 'gutenberg_filter_template_list_table_columns' );

/**
* Renders column content for the 'wp_template' post type list table.
*
* @param string $column_name Column name to render.
* @param int $post_id Post ID.
*/
function gutenberg_render_template_list_table_column( $column_name, $post_id ) {
if ( 'slug' !== $column_name ) {
return;
}
$post = get_post( $post_id );
echo esc_html( $post->post_name );
}
add_action( 'manage_wp_template_posts_custom_column', 'gutenberg_render_template_list_table_column', 10, 2 );
17 changes: 17 additions & 0 deletions packages/edit-post/src/components/sidebar/post-slug/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* WordPress dependencies
*/
import { PanelRow } from '@wordpress/components';
import { PostSlug as PostSlugForm, PostSlugCheck } from '@wordpress/editor';

export function PostSlug() {
return (
<PostSlugCheck>
<PanelRow>
<PostSlugForm />
</PanelRow>
</PostSlugCheck>
);
}

export default PostSlug;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.editor-post-slug__input {
margin: -5px 0;
padding: 2px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import PostTrash from '../post-trash';
import PostSchedule from '../post-schedule';
import PostSticky from '../post-sticky';
import PostAuthor from '../post-author';
import PostSlug from '../post-slug';
import PostFormat from '../post-format';
import PostPendingStatus from '../post-pending-status';
import PluginPostStatusInfo from '../plugin-post-status-info';
Expand All @@ -34,6 +35,7 @@ function PostStatus( { isOpened, onTogglePanel } ) {
<PostFormat />
<PostSticky />
<PostPendingStatus />
<PostSlug />
<PostAuthor />
{ fills }
<PostTrash />
Expand Down
1 change: 1 addition & 0 deletions packages/edit-post/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
@import "./components/sidebar/post-author/style.scss";
@import "./components/sidebar/post-link/style.scss";
@import "./components/sidebar/post-schedule/style.scss";
@import "./components/sidebar/post-slug/style.scss";
@import "./components/sidebar/post-status/style.scss";
@import "./components/sidebar/post-visibility/style.scss";
@import "./components/sidebar/settings-header/style.scss";
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export { default as PostSavedState } from './post-saved-state';
export { default as PostSchedule } from './post-schedule';
export { default as PostScheduleCheck } from './post-schedule/check';
export { default as PostScheduleLabel } from './post-schedule/label';
export { default as PostSlug } from './post-slug';
export { default as PostSlugCheck } from './post-slug/check';
export { default as PostSticky } from './post-sticky';
export { default as PostStickyCheck } from './post-sticky/check';
export { default as PostSwitchToDraftButton } from './post-switch-to-draft-button';
Expand Down
10 changes: 10 additions & 0 deletions packages/editor/src/components/post-slug/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Internal dependencies
*/
import PostTypeSupportCheck from '../post-type-support-check';

export default function PostSlugCheck( { children } ) {
return (
<PostTypeSupportCheck supportKeys="slug">{ children }</PostTypeSupportCheck>
);
}
85 changes: 85 additions & 0 deletions packages/editor/src/components/post-slug/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* WordPress dependencies
*/
import { withDispatch, withSelect } from '@wordpress/data';
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { withInstanceId, compose } from '@wordpress/compose';
import { safeDecodeURIComponent } from '@wordpress/url';

/**
* Internal dependencies
*/
import PostSlugCheck from './check';
import { cleanForSlug } from '../../utils/url';

export class PostSlug extends Component {
constructor( { postSlug, postTitle, postID } ) {
super( ...arguments );

this.state = {
editedSlug: safeDecodeURIComponent( postSlug ) || cleanForSlug( postTitle ) || postID,
};

this.setSlug = this.setSlug.bind( this );
}

setSlug( event ) {
const { postSlug, onUpdateSlug } = this.props;
const { value } = event.target;

const editedSlug = cleanForSlug( value );

if ( editedSlug === postSlug ) {
return;
}

onUpdateSlug( editedSlug );
}

render() {
const { instanceId } = this.props;
const { editedSlug } = this.state;

const inputId = 'editor-post-slug-' + instanceId;

return (
<PostSlugCheck>
<label htmlFor={ inputId }>{ __( 'Slug' ) }</label>
<input
type="text"
id={ inputId }
value={ editedSlug }
onChange={ ( event ) => this.setState( { editedSlug: event.target.value } ) }
onBlur={ this.setSlug }
className="editor-post-slug__input"
/>
</PostSlugCheck>
);
}
}

export default compose( [
withSelect( ( select ) => {
const {
getCurrentPost,
getEditedPostAttribute,
} = select( 'core/editor' );

const { id } = getCurrentPost();
return {
postSlug: getEditedPostAttribute( 'slug' ),
postTitle: getEditedPostAttribute( 'title' ),
postID: id,
};
} ),
withDispatch( ( dispatch ) => {
const { editPost } = dispatch( 'core/editor' );
return {
onUpdateSlug( slug ) {
editPost( { slug } );
},
};
} ),
withInstanceId,
] )( PostSlug );
21 changes: 21 additions & 0 deletions packages/editor/src/components/post-slug/test/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* Internal dependencies
*/
import PostSlugCheck from '../check';

describe( 'PostSlugCheck', () => {
it( 'should render control', () => {
const wrapper = shallow(
<PostSlugCheck>
slug
</PostSlugCheck>
);

expect( wrapper.type() ).not.toBe( null );
} );
} );
45 changes: 45 additions & 0 deletions packages/editor/src/components/post-slug/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* Internal dependencies
*/
import { PostSlug } from '../';

describe( 'PostSlug', () => {
describe( '#render()', () => {
it( 'should update internal slug', () => {
const wrapper = shallow(
<PostSlug
postSlug="index" />
);

wrapper.find( 'input' ).simulate( 'change', {
target: {
value: 'single-post',
},
} );

expect( wrapper.state().editedSlug ).toEqual( 'single-post' );
} );

it( 'should update slug', () => {
const onUpdateSlug = jest.fn();
const wrapper = shallow(
<PostSlug
postSlug="index"
onUpdateSlug={ onUpdateSlug } />
);

wrapper.find( 'input' ).simulate( 'blur', {
target: {
value: 'single-post',
},
} );

expect( onUpdateSlug ).toHaveBeenCalledWith( 'single-post' );
} );
} );
} );

0 comments on commit 6cf43ac

Please sign in to comment.