Version Description
- Latest round of updates
Download this release
Release Info
Developer | obenland |
Plugin | Full Site Editing |
Version | 0.1.1 |
Comparing to | |
See all releases |
Code changes from version 0.1 to 0.1.1
- full-site-editing-plugin.php +16 -2
- full-site-editing/blocks/post-content/edit.js +104 -0
- full-site-editing/blocks/post-content/index.js +30 -0
- full-site-editing/blocks/post-content/index.php +43 -0
- full-site-editing/blocks/post-content/style.scss +21 -0
- full-site-editing/blocks/template/edit.js +98 -0
- full-site-editing/blocks/template/index.js +30 -0
- full-site-editing/blocks/template/index.php +37 -0
- full-site-editing/blocks/template/style.scss +21 -0
- full-site-editing/class-a8c-rest-templates-controller.php +47 -0
- full-site-editing/class-full-site-editing.php +305 -0
- full-site-editing/components/post-autocomplete/index.js +113 -0
- full-site-editing/components/post-autocomplete/style.scss +24 -0
- full-site-editing/dist/full-site-editing.css +1 -0
- full-site-editing/dist/full-site-editing.deps.json +1 -0
- full-site-editing/dist/full-site-editing.js +12 -0
- full-site-editing/dist/full-site-editing.rtl.css +1 -0
- full-site-editing/index.js +6 -0
- full-site-editing/plugins/template-selector-sidebar/index.js +71 -0
- lib/feature-flags/feature-flags.php +116 -0
- lib/feature-flags/index.js +9 -0
- readme.txt +4 -1
- starter-page-templates/class-starter-page-templates.php +1 -0
- starter-page-templates/dist/starter-page-templates.css +1 -1
- starter-page-templates/dist/starter-page-templates.deps.json +1 -1
- starter-page-templates/dist/starter-page-templates.js +2 -2
- starter-page-templates/dist/starter-page-templates.rtl.css +1 -1
- starter-page-templates/page-template-modal/components/template-selector-control.js +25 -23
- starter-page-templates/page-template-modal/index.js +93 -68
- starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +12 -5
- starter-page-templates/page-template-modal/utils/replace-placeholders.js +9 -4
full-site-editing-plugin.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/**
|
3 |
* Plugin Name: Full Site Editing
|
4 |
* Description: Enhances your page creation workflow within the Block Editor.
|
5 |
-
* Version: 0.1
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com/wordpress-plugins/
|
8 |
* License: GPLv2 or later
|
@@ -11,6 +11,20 @@
|
|
11 |
* @package full-site-editing
|
12 |
*/
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
/**
|
15 |
* Load Posts List Block.
|
16 |
*/
|
@@ -42,4 +56,4 @@ function a8c_load_starter_page_templates() {
|
|
42 |
|
43 |
Starter_Page_Templates::get_instance();
|
44 |
}
|
45 |
-
add_action( 'plugins_loaded', 'a8c_load_starter_page_templates' );
|
2 |
/**
|
3 |
* Plugin Name: Full Site Editing
|
4 |
* Description: Enhances your page creation workflow within the Block Editor.
|
5 |
+
* Version: 0.1.1
|
6 |
* Author: Automattic
|
7 |
* Author URI: https://automattic.com/wordpress-plugins/
|
8 |
* License: GPLv2 or later
|
11 |
* @package full-site-editing
|
12 |
*/
|
13 |
|
14 |
+
/**
|
15 |
+
* Load Full Site Editing.
|
16 |
+
*/
|
17 |
+
function a8c_load_full_site_editing() {
|
18 |
+
require_once __DIR__ . '/lib/feature-flags/feature-flags.php';
|
19 |
+
require_once __DIR__ . '/full-site-editing/blocks/post-content/index.php';
|
20 |
+
require_once __DIR__ . '/full-site-editing/blocks/template/index.php';
|
21 |
+
require_once __DIR__ . '/full-site-editing/class-a8c-rest-templates-controller.php';
|
22 |
+
require_once __DIR__ . '/full-site-editing/class-full-site-editing.php';
|
23 |
+
|
24 |
+
Full_Site_Editing::get_instance();
|
25 |
+
}
|
26 |
+
//add_action( 'plugins_loaded', 'a8c_load_full_site_editing' );
|
27 |
+
|
28 |
/**
|
29 |
* Load Posts List Block.
|
30 |
*/
|
56 |
|
57 |
Starter_Page_Templates::get_instance();
|
58 |
}
|
59 |
+
//add_action( 'plugins_loaded', 'a8c_load_starter_page_templates' );
|
full-site-editing/blocks/post-content/edit.js
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint-disable wpcalypso/jsx-classname-namespace */
|
2 |
+
/**
|
3 |
+
* External dependencies
|
4 |
+
*/
|
5 |
+
import classNames from 'classnames';
|
6 |
+
import { get } from 'lodash';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* WordPress dependencies
|
10 |
+
*/
|
11 |
+
import { IconButton, Placeholder, Toolbar } from '@wordpress/components';
|
12 |
+
import { compose, withState } from '@wordpress/compose';
|
13 |
+
import { withSelect } from '@wordpress/data';
|
14 |
+
import { BlockControls } from '@wordpress/editor';
|
15 |
+
import { Fragment, RawHTML } from '@wordpress/element';
|
16 |
+
import { __, sprintf } from '@wordpress/i18n';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Internal dependencies
|
20 |
+
*/
|
21 |
+
import PostAutocomplete from '../../components/post-autocomplete';
|
22 |
+
|
23 |
+
const PostContentEdit = compose(
|
24 |
+
withState( {
|
25 |
+
isEditing: false,
|
26 |
+
selectedPostId: undefined,
|
27 |
+
selectedPostType: undefined,
|
28 |
+
} ),
|
29 |
+
withSelect( ( select, { selectedPostId, selectedPostType } ) => {
|
30 |
+
const { getEntityRecord } = select( 'core' );
|
31 |
+
return {
|
32 |
+
selectedPost: getEntityRecord( 'postType', selectedPostType, selectedPostId ),
|
33 |
+
};
|
34 |
+
} )
|
35 |
+
)( ( { attributes, isEditing, selectedPost, setState } ) => {
|
36 |
+
const { align } = attributes;
|
37 |
+
|
38 |
+
const toggleEditing = () => setState( { isEditing: ! isEditing } );
|
39 |
+
|
40 |
+
const onSelectPost = ( { id, type } ) => {
|
41 |
+
setState( {
|
42 |
+
isEditing: false,
|
43 |
+
selectedPostId: id,
|
44 |
+
selectedPostType: type,
|
45 |
+
} );
|
46 |
+
};
|
47 |
+
|
48 |
+
const showToggleButton = ! isEditing || !! selectedPost;
|
49 |
+
const showPlaceholder = isEditing || ! selectedPost;
|
50 |
+
const showPreview = ! isEditing && !! selectedPost;
|
51 |
+
|
52 |
+
return (
|
53 |
+
<Fragment>
|
54 |
+
{ showToggleButton && (
|
55 |
+
<BlockControls>
|
56 |
+
<Toolbar>
|
57 |
+
<IconButton
|
58 |
+
className={ classNames( 'components-icon-button components-toolbar__control', {
|
59 |
+
'is-active': isEditing,
|
60 |
+
} ) }
|
61 |
+
label={ __( 'Change Preview' ) }
|
62 |
+
onClick={ toggleEditing }
|
63 |
+
icon="edit"
|
64 |
+
/>
|
65 |
+
</Toolbar>
|
66 |
+
</BlockControls>
|
67 |
+
) }
|
68 |
+
<div
|
69 |
+
className={ classNames( 'post-content-block', {
|
70 |
+
[ `align${ align }` ]: align,
|
71 |
+
} ) }
|
72 |
+
>
|
73 |
+
{ showPlaceholder && (
|
74 |
+
<Placeholder
|
75 |
+
icon="layout"
|
76 |
+
label={ __( 'Content Slot' ) }
|
77 |
+
instructions={ __( 'Placeholder for a post or a page.' ) }
|
78 |
+
>
|
79 |
+
<div className="post-content-block__selector">
|
80 |
+
<div>{ __( 'Select something to preview:' ) }</div>
|
81 |
+
<PostAutocomplete
|
82 |
+
initialValue={ get( selectedPost, [ 'title', 'rendered' ] ) }
|
83 |
+
onSelectPost={ onSelectPost }
|
84 |
+
postType={ [ 'page', 'post' ] }
|
85 |
+
/>
|
86 |
+
{ !! selectedPost && (
|
87 |
+
<a href={ `?post=${ selectedPost.id }&action=edit` }>
|
88 |
+
{ sprintf( __( 'Edit "%s"' ), get( selectedPost, [ 'title', 'rendered' ], '' ) ) }
|
89 |
+
</a>
|
90 |
+
) }
|
91 |
+
</div>
|
92 |
+
</Placeholder>
|
93 |
+
) }
|
94 |
+
{ showPreview && (
|
95 |
+
<RawHTML className="post-content-block__preview">
|
96 |
+
{ get( selectedPost, [ 'content', 'rendered' ] ) }
|
97 |
+
</RawHTML>
|
98 |
+
) }
|
99 |
+
</div>
|
100 |
+
</Fragment>
|
101 |
+
);
|
102 |
+
} );
|
103 |
+
|
104 |
+
export default PostContentEdit;
|
full-site-editing/blocks/post-content/index.js
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global fullSiteEditing */
|
2 |
+
/**
|
3 |
+
* WordPress dependencies
|
4 |
+
*/
|
5 |
+
import { registerBlockType } from '@wordpress/blocks';
|
6 |
+
import { __ } from '@wordpress/i18n';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Internal dependencies
|
10 |
+
*/
|
11 |
+
import edit from './edit';
|
12 |
+
import './style.scss';
|
13 |
+
|
14 |
+
if ( 'wp_template' === fullSiteEditing.editorPostType ) {
|
15 |
+
registerBlockType( 'a8c/post-content', {
|
16 |
+
title: __( 'Content Slot' ),
|
17 |
+
description: __( 'Placeholder for a post or a page.' ),
|
18 |
+
icon: 'layout',
|
19 |
+
category: 'layout',
|
20 |
+
supports: {
|
21 |
+
align: [ 'wide', 'full' ],
|
22 |
+
anchor: true,
|
23 |
+
html: false,
|
24 |
+
multiple: false,
|
25 |
+
reusable: false,
|
26 |
+
},
|
27 |
+
edit,
|
28 |
+
save: () => null,
|
29 |
+
} );
|
30 |
+
}
|
full-site-editing/blocks/post-content/index.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Render post content block file.
|
4 |
+
*
|
5 |
+
* @package full-site-editing
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Renders post content.
|
10 |
+
*
|
11 |
+
* @param array $attributes Block attributes.
|
12 |
+
* @param string $content Block content.
|
13 |
+
* @return string
|
14 |
+
*/
|
15 |
+
function render_post_content_block( $attributes, $content ) {
|
16 |
+
// Early return to avoid infinite loops in the REST API
|
17 |
+
if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
|
18 |
+
return $content;
|
19 |
+
}
|
20 |
+
|
21 |
+
$post_id = get_the_ID();
|
22 |
+
$post_type = get_post_type();
|
23 |
+
$template_id = get_post_meta( $post_id, '_wp_template_id', true );
|
24 |
+
|
25 |
+
// Early return to avoid the infinite loop of a template rendering itself.
|
26 |
+
if ( 'wp_template' === $post_type || $template_id === $post_id ) {
|
27 |
+
return $content;
|
28 |
+
}
|
29 |
+
|
30 |
+
$align = isset( $attributes['align'] ) ? ' align' . $attributes['align'] : '';
|
31 |
+
|
32 |
+
ob_start();
|
33 |
+
?>
|
34 |
+
|
35 |
+
<div class="post-content<?php echo $align; ?>">
|
36 |
+
<?php echo apply_filters( 'the_content', get_the_content() ); ?>
|
37 |
+
</div><!-- .post-content -->
|
38 |
+
|
39 |
+
<?php
|
40 |
+
$content = ob_get_clean();
|
41 |
+
|
42 |
+
return $content;
|
43 |
+
}
|
full-site-editing/blocks/post-content/style.scss
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.post-content-block.alignfull {
|
2 |
+
padding: 0 12px;
|
3 |
+
}
|
4 |
+
|
5 |
+
.post-content-block__selector {
|
6 |
+
width: 300px;
|
7 |
+
a {
|
8 |
+
font-family: sans-serif;
|
9 |
+
font-size: 13px;
|
10 |
+
padding-left: 8px;
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
.post-content-block__preview {
|
15 |
+
pointer-events: none;
|
16 |
+
&::after {
|
17 |
+
content: '';
|
18 |
+
clear: both;
|
19 |
+
display: table;
|
20 |
+
}
|
21 |
+
}
|
full-site-editing/blocks/template/edit.js
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint-disable wpcalypso/jsx-classname-namespace */
|
2 |
+
/**
|
3 |
+
* External dependencies
|
4 |
+
*/
|
5 |
+
import classNames from 'classnames';
|
6 |
+
import { get } from 'lodash';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* WordPress dependencies
|
10 |
+
*/
|
11 |
+
import { IconButton, Placeholder, Toolbar } from '@wordpress/components';
|
12 |
+
import { compose, withState } from '@wordpress/compose';
|
13 |
+
import { withSelect } from '@wordpress/data';
|
14 |
+
import { BlockControls } from '@wordpress/editor';
|
15 |
+
import { Fragment, RawHTML } from '@wordpress/element';
|
16 |
+
import { __, sprintf } from '@wordpress/i18n';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Internal dependencies
|
20 |
+
*/
|
21 |
+
import PostAutocomplete from '../../components/post-autocomplete';
|
22 |
+
import './style.scss';
|
23 |
+
|
24 |
+
const TemplateEdit = compose(
|
25 |
+
withSelect( ( select, { attributes } ) => {
|
26 |
+
const { getEntityRecord } = select( 'core' );
|
27 |
+
const { templateId } = attributes;
|
28 |
+
return {
|
29 |
+
template: templateId && getEntityRecord( 'postType', 'wp_template_part', templateId ),
|
30 |
+
};
|
31 |
+
} ),
|
32 |
+
withState( { isEditing: false } )
|
33 |
+
)( ( { attributes, isEditing, template, setAttributes, setState } ) => {
|
34 |
+
const { align, templateId } = attributes;
|
35 |
+
|
36 |
+
const toggleEditing = () => setState( { isEditing: ! isEditing } );
|
37 |
+
|
38 |
+
const onSelectTemplate = ( { id } ) => {
|
39 |
+
setState( { isEditing: false } );
|
40 |
+
setAttributes( { templateId: id } );
|
41 |
+
};
|
42 |
+
|
43 |
+
const showToggleButton = ! isEditing || !! templateId;
|
44 |
+
const showPlaceholder = isEditing || ! templateId;
|
45 |
+
const showContent = ! isEditing && !! templateId;
|
46 |
+
|
47 |
+
return (
|
48 |
+
<Fragment>
|
49 |
+
{ showToggleButton && (
|
50 |
+
<BlockControls>
|
51 |
+
<Toolbar>
|
52 |
+
<IconButton
|
53 |
+
className={ classNames( 'components-icon-button components-toolbar__control', {
|
54 |
+
'is-active': isEditing,
|
55 |
+
} ) }
|
56 |
+
label={ __( 'Change Template Part' ) }
|
57 |
+
onClick={ toggleEditing }
|
58 |
+
icon="edit"
|
59 |
+
/>
|
60 |
+
</Toolbar>
|
61 |
+
</BlockControls>
|
62 |
+
) }
|
63 |
+
<div
|
64 |
+
className={ classNames( 'template-block', {
|
65 |
+
[ `align${ align }` ]: align,
|
66 |
+
} ) }
|
67 |
+
>
|
68 |
+
{ showPlaceholder && (
|
69 |
+
<Placeholder
|
70 |
+
icon="layout"
|
71 |
+
label={ __( 'Template Part' ) }
|
72 |
+
instructions={ __( 'Select a template part to display' ) }
|
73 |
+
>
|
74 |
+
<div className="template-block__selector">
|
75 |
+
<PostAutocomplete
|
76 |
+
initialValue={ get( template, [ 'title', 'rendered' ] ) }
|
77 |
+
onSelectPost={ onSelectTemplate }
|
78 |
+
postType="wp_template_part"
|
79 |
+
/>
|
80 |
+
{ !! template && (
|
81 |
+
<a href={ `?post=${ templateId }&action=edit` }>
|
82 |
+
{ sprintf( __( 'Edit "%s"' ), get( template, [ 'title', 'rendered' ], '' ) ) }
|
83 |
+
</a>
|
84 |
+
) }
|
85 |
+
</div>
|
86 |
+
</Placeholder>
|
87 |
+
) }
|
88 |
+
{ showContent && (
|
89 |
+
<RawHTML className="template-block__content">
|
90 |
+
{ get( template, [ 'content', 'rendered' ] ) }
|
91 |
+
</RawHTML>
|
92 |
+
) }
|
93 |
+
</div>
|
94 |
+
</Fragment>
|
95 |
+
);
|
96 |
+
} );
|
97 |
+
|
98 |
+
export default TemplateEdit;
|
full-site-editing/blocks/template/index.js
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global fullSiteEditing */
|
2 |
+
/**
|
3 |
+
* WordPress dependencies
|
4 |
+
*/
|
5 |
+
import { registerBlockType } from '@wordpress/blocks';
|
6 |
+
import { __ } from '@wordpress/i18n';
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Internal dependencies
|
10 |
+
*/
|
11 |
+
import edit from './edit';
|
12 |
+
import './style.scss';
|
13 |
+
|
14 |
+
if ( 'wp_template' === fullSiteEditing.editorPostType ) {
|
15 |
+
registerBlockType( 'a8c/template', {
|
16 |
+
title: __( 'Template Part' ),
|
17 |
+
description: __( 'Display a template part.' ),
|
18 |
+
icon: 'layout',
|
19 |
+
category: 'layout',
|
20 |
+
attributes: { templateId: { type: 'number' } },
|
21 |
+
supports: {
|
22 |
+
align: [ 'wide', 'full' ],
|
23 |
+
anchor: true,
|
24 |
+
html: false,
|
25 |
+
reusable: false,
|
26 |
+
},
|
27 |
+
edit,
|
28 |
+
save: () => null,
|
29 |
+
} );
|
30 |
+
}
|
full-site-editing/blocks/template/index.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Render template block file.
|
4 |
+
*
|
5 |
+
* @package full-site-editing
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Renders template.
|
10 |
+
*
|
11 |
+
* @param array $attributes Block attributes.
|
12 |
+
* @return string
|
13 |
+
*/
|
14 |
+
function render_template_block( $attributes ) {
|
15 |
+
if ( ! isset( $attributes['templateId'] ) || ! is_int( $attributes['templateId'] ) ) {
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
|
19 |
+
$parent_post_id = get_the_ID();
|
20 |
+
$template = get_post( $attributes['templateId'] );
|
21 |
+
|
22 |
+
$align = isset( $attributes['align'] ) ? ' align' . $attributes['align'] : '';
|
23 |
+
|
24 |
+
setup_postdata( $template );
|
25 |
+
ob_start();
|
26 |
+
?>
|
27 |
+
|
28 |
+
<div class="template-part<?php echo $align; ?>">
|
29 |
+
<?php echo apply_filters( 'the_content', get_the_content() ); ?>
|
30 |
+
</div><!-- .template-part -->
|
31 |
+
|
32 |
+
<?php
|
33 |
+
$content = ob_get_clean();
|
34 |
+
wp_reset_postdata();
|
35 |
+
|
36 |
+
return $content;
|
37 |
+
}
|
full-site-editing/blocks/template/style.scss
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.template-block.alignfull {
|
2 |
+
padding: 0 12px;
|
3 |
+
}
|
4 |
+
|
5 |
+
.template-block__selector {
|
6 |
+
width: 300px;
|
7 |
+
a {
|
8 |
+
font-family: sans-serif;
|
9 |
+
font-size: 13px;
|
10 |
+
padding-left: 8px;
|
11 |
+
}
|
12 |
+
}
|
13 |
+
|
14 |
+
.template-block__content {
|
15 |
+
pointer-events: none;
|
16 |
+
&::after {
|
17 |
+
content: '';
|
18 |
+
clear: both;
|
19 |
+
display: table;
|
20 |
+
}
|
21 |
+
}
|
full-site-editing/class-a8c-rest-templates-controller.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* A8C REST Templates Controller file.
|
4 |
+
*
|
5 |
+
* @package full-site-editing
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Based on `WP_REST_Blocks_Controller` from core
|
10 |
+
*/
|
11 |
+
class A8C_REST_Templates_Controller extends WP_REST_Posts_Controller {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Checks if a template can be read.
|
15 |
+
*
|
16 |
+
* @param object $post Post object that backs the template.
|
17 |
+
* @return bool Whether the template can be read.
|
18 |
+
*/
|
19 |
+
public function check_read_permission( $post ) {
|
20 |
+
// Ensure that the user is logged in and has the edit_posts capability.
|
21 |
+
$post_type = get_post_type_object( $post->post_type );
|
22 |
+
if ( ! current_user_can( $post_type->cap->read_post, $post->ID ) ) {
|
23 |
+
return false;
|
24 |
+
}
|
25 |
+
|
26 |
+
return parent::check_read_permission( $post );
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Retrieves the template's schema, conforming to JSON Schema.
|
31 |
+
*
|
32 |
+
* @return array Item schema data.
|
33 |
+
*/
|
34 |
+
public function get_item_schema() {
|
35 |
+
$schema = parent::get_item_schema();
|
36 |
+
|
37 |
+
/*
|
38 |
+
* Allow all contexts to access `title.raw` and `content.raw`. Clients always
|
39 |
+
* need the raw markup of a reusable template to do anything useful, e.g. parse
|
40 |
+
* it or display it in an editor.
|
41 |
+
*/
|
42 |
+
$schema['properties']['title']['properties']['raw']['context'] = array( 'view', 'edit' );
|
43 |
+
$schema['properties']['content']['properties']['raw']['context'] = array( 'view', 'edit' );
|
44 |
+
|
45 |
+
return $schema;
|
46 |
+
}
|
47 |
+
}
|
full-site-editing/class-full-site-editing.php
ADDED
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Full site editing file.
|
4 |
+
*
|
5 |
+
* @package full-site-editing
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class Full_Site_Editing
|
10 |
+
*/
|
11 |
+
class Full_Site_Editing {
|
12 |
+
/**
|
13 |
+
* Class instance.
|
14 |
+
*
|
15 |
+
* @var Full_Site_Editing
|
16 |
+
*/
|
17 |
+
private static $instance = null;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Full_Site_Editing constructor.
|
21 |
+
*/
|
22 |
+
private function __construct() {
|
23 |
+
add_action( 'init', array( $this, 'register_blocks' ), 100 );
|
24 |
+
add_action( 'init', array( $this, 'register_template_post_types' ) );
|
25 |
+
add_action( 'init', array( $this, 'register_meta_template_id' ) );
|
26 |
+
add_action( 'rest_api_init', array( $this, 'allow_searching_for_templates' ) );
|
27 |
+
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_script_and_style' ), 100 );
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Creates instance.
|
32 |
+
*
|
33 |
+
* @return \Full_Site_Editing
|
34 |
+
*/
|
35 |
+
public static function get_instance() {
|
36 |
+
if ( null === self::$instance ) {
|
37 |
+
self::$instance = new self();
|
38 |
+
}
|
39 |
+
|
40 |
+
return self::$instance;
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Register post types.
|
45 |
+
*/
|
46 |
+
public function register_template_post_types() {
|
47 |
+
register_post_type(
|
48 |
+
'wp_template',
|
49 |
+
array(
|
50 |
+
'labels' => array(
|
51 |
+
'name' => _x( 'Templates', 'post type general name', 'full-site-editing' ),
|
52 |
+
'singular_name' => _x( 'Template', 'post type singular name', 'full-site-editing' ),
|
53 |
+
'menu_name' => _x( 'Templates', 'admin menu', 'full-site-editing' ),
|
54 |
+
'name_admin_bar' => _x( 'Template', 'add new on admin bar', 'full-site-editing' ),
|
55 |
+
'add_new' => _x( 'Add New', 'Template', 'full-site-editing' ),
|
56 |
+
'add_new_item' => __( 'Add New Template', 'full-site-editing' ),
|
57 |
+
'new_item' => __( 'New Template', 'full-site-editing' ),
|
58 |
+
'edit_item' => __( 'Edit Template', 'full-site-editing' ),
|
59 |
+
'view_item' => __( 'View Template', 'full-site-editing' ),
|
60 |
+
'all_items' => __( 'All Templates', 'full-site-editing' ),
|
61 |
+
'search_items' => __( 'Search Templates', 'full-site-editing' ),
|
62 |
+
'not_found' => __( 'No templates found.', 'full-site-editing' ),
|
63 |
+
'not_found_in_trash' => __( 'No templates found in Trash.', 'full-site-editing' ),
|
64 |
+
'filter_items_list' => __( 'Filter templates list', 'full-site-editing' ),
|
65 |
+
'items_list_navigation' => __( 'Templates list navigation', 'full-site-editing' ),
|
66 |
+
'items_list' => __( 'Templates list', 'full-site-editing' ),
|
67 |
+
'item_published' => __( 'Template published.', 'full-site-editing' ),
|
68 |
+
'item_published_privately' => __( 'Template published privately.', 'full-site-editing' ),
|
69 |
+
'item_reverted_to_draft' => __( 'Template reverted to draft.', 'full-site-editing' ),
|
70 |
+
'item_scheduled' => __( 'Template scheduled.', 'full-site-editing' ),
|
71 |
+
'item_updated' => __( 'Template updated.', 'full-site-editing' ),
|
72 |
+
),
|
73 |
+
'menu_icon' => 'dashicons-layout',
|
74 |
+
'public' => false,
|
75 |
+
'show_ui' => true,
|
76 |
+
'show_in_menu' => true,
|
77 |
+
'rewrite' => false,
|
78 |
+
'show_in_rest' => true,
|
79 |
+
'rest_base' => 'templates',
|
80 |
+
'rest_controller_class' => 'A8C_REST_Templates_Controller',
|
81 |
+
'capability_type' => 'template',
|
82 |
+
'capabilities' => array(
|
83 |
+
// You need to be able to edit posts, in order to read templates in their raw form.
|
84 |
+
'read' => 'edit_posts',
|
85 |
+
// You need to be able to customize, in order to create templates.
|
86 |
+
'create_posts' => 'edit_theme_options',
|
87 |
+
'edit_posts' => 'edit_theme_options',
|
88 |
+
'delete_posts' => 'edit_theme_options',
|
89 |
+
'edit_published_posts' => 'edit_theme_options',
|
90 |
+
'delete_published_posts' => 'edit_theme_options',
|
91 |
+
'edit_others_posts' => 'edit_theme_options',
|
92 |
+
'delete_others_posts' => 'edit_theme_options',
|
93 |
+
'publish_posts' => 'edit_theme_options',
|
94 |
+
),
|
95 |
+
'map_meta_cap' => true,
|
96 |
+
'supports' => array(
|
97 |
+
'title',
|
98 |
+
'editor',
|
99 |
+
),
|
100 |
+
)
|
101 |
+
);
|
102 |
+
|
103 |
+
register_post_type(
|
104 |
+
'wp_template_part',
|
105 |
+
array(
|
106 |
+
'labels' => array(
|
107 |
+
'name' => _x( 'Template Parts', 'post type general name', 'full-site-editing' ),
|
108 |
+
'singular_name' => _x( 'Template Part', 'post type singular name', 'full-site-editing' ),
|
109 |
+
'menu_name' => _x( 'Template Parts', 'admin menu', 'full-site-editing' ),
|
110 |
+
'name_admin_bar' => _x( 'Template Part', 'add new on admin bar', 'full-site-editing' ),
|
111 |
+
'add_new' => _x( 'Add New', 'Template Part', 'full-site-editing' ),
|
112 |
+
'add_new_item' => __( 'Add New Template Part', 'full-site-editing' ),
|
113 |
+
'new_item' => __( 'New Template Part', 'full-site-editing' ),
|
114 |
+
'edit_item' => __( 'Edit Template Part', 'full-site-editing' ),
|
115 |
+
'view_item' => __( 'View Template Part', 'full-site-editing' ),
|
116 |
+
'all_items' => __( 'All Template Parts', 'full-site-editing' ),
|
117 |
+
'search_items' => __( 'Search Template Parts', 'full-site-editing' ),
|
118 |
+
'not_found' => __( 'No template parts found.', 'full-site-editing' ),
|
119 |
+
'not_found_in_trash' => __( 'No template parts found in Trash.', 'full-site-editing' ),
|
120 |
+
'filter_items_list' => __( 'Filter template parts list', 'full-site-editing' ),
|
121 |
+
'items_list_navigation' => __( 'Template parts list navigation', 'full-site-editing' ),
|
122 |
+
'items_list' => __( 'Template parts list', 'full-site-editing' ),
|
123 |
+
'item_published' => __( 'Template part published.', 'full-site-editing' ),
|
124 |
+
'item_published_privately' => __( 'Template part published privately.', 'full-site-editing' ),
|
125 |
+
'item_reverted_to_draft' => __( 'Template part reverted to draft.', 'full-site-editing' ),
|
126 |
+
'item_scheduled' => __( 'Template part scheduled.', 'full-site-editing' ),
|
127 |
+
'item_updated' => __( 'Template part updated.', 'full-site-editing' ),
|
128 |
+
),
|
129 |
+
'menu_icon' => 'dashicons-layout',
|
130 |
+
'public' => false,
|
131 |
+
'show_ui' => true,
|
132 |
+
'show_in_menu' => true,
|
133 |
+
'rewrite' => false,
|
134 |
+
'show_in_rest' => true,
|
135 |
+
'rest_base' => 'template_parts',
|
136 |
+
'rest_controller_class' => 'A8C_REST_Templates_Controller',
|
137 |
+
'capability_type' => 'template_part',
|
138 |
+
'capabilities' => array(
|
139 |
+
// You need to be able to edit posts, in order to read templates in their raw form.
|
140 |
+
'read' => 'edit_posts',
|
141 |
+
// You need to be able to customize, in order to create templates.
|
142 |
+
'create_posts' => 'edit_theme_options',
|
143 |
+
'edit_posts' => 'edit_theme_options',
|
144 |
+
'delete_posts' => 'edit_theme_options',
|
145 |
+
'edit_published_posts' => 'edit_theme_options',
|
146 |
+
'delete_published_posts' => 'edit_theme_options',
|
147 |
+
'edit_others_posts' => 'edit_theme_options',
|
148 |
+
'delete_others_posts' => 'edit_theme_options',
|
149 |
+
'publish_posts' => 'edit_theme_options',
|
150 |
+
),
|
151 |
+
'map_meta_cap' => true,
|
152 |
+
'supports' => array(
|
153 |
+
'title',
|
154 |
+
'editor',
|
155 |
+
),
|
156 |
+
)
|
157 |
+
);
|
158 |
+
|
159 |
+
register_taxonomy(
|
160 |
+
'wp_template_part_type',
|
161 |
+
'wp_template_part',
|
162 |
+
array(
|
163 |
+
'labels' => array(
|
164 |
+
'name' => _x( 'Template Part Types', 'taxonomy general name', 'full-site-editing' ),
|
165 |
+
'singular_name' => _x( 'Template Part Type', 'taxonomy singular name', 'full-site-editing' ),
|
166 |
+
'menu_name' => _x( 'Template Part Types', 'admin menu', 'full-site-editing' ),
|
167 |
+
'all_items' => __( 'All Template Part Types', 'full-site-editing' ),
|
168 |
+
'edit_item' => __( 'Edit Template Part Type', 'full-site-editing' ),
|
169 |
+
'view_item' => __( 'View Template Part Type', 'full-site-editing' ),
|
170 |
+
'update_item' => __( 'Update Template Part Type', 'full-site-editing' ),
|
171 |
+
'add_new_item' => __( 'Add New Template Part Type', 'full-site-editing' ),
|
172 |
+
'new_item_name' => __( 'New Template Part Type', 'full-site-editing' ),
|
173 |
+
'parent_item' => __( 'Parent Template Part Type', 'full-site-editing' ),
|
174 |
+
'parent_item_colon' => __( 'Parent Template Part Type:', 'full-site-editing' ),
|
175 |
+
'search_items' => __( 'Search Template Part Types', 'full-site-editing' ),
|
176 |
+
'not_found' => __( 'No template part types found.', 'full-site-editing' ),
|
177 |
+
'back_to_items' => __( 'Back to template part types', 'full-site-editing' ),
|
178 |
+
),
|
179 |
+
'public' => false,
|
180 |
+
'publicly_queryable' => true,
|
181 |
+
'show_ui' => true,
|
182 |
+
'show_in_menu' => false,
|
183 |
+
'show_in_nav_menu' => false,
|
184 |
+
'show_in_rest' => true,
|
185 |
+
'rest_base' => 'template_part_types',
|
186 |
+
'show_tagcloud' => false,
|
187 |
+
'show_admin_column' => true,
|
188 |
+
'hierarchical' => true,
|
189 |
+
'rewrite' => false,
|
190 |
+
'capabilities' => array(
|
191 |
+
'manage_terms' => 'edit_theme_options',
|
192 |
+
'edit_terms' => 'edit_theme_options',
|
193 |
+
'delete_terms' => 'edit_theme_options',
|
194 |
+
'assign_terms' => 'edit_theme_options',
|
195 |
+
),
|
196 |
+
)
|
197 |
+
);
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Register post meta.
|
202 |
+
*/
|
203 |
+
public function register_meta_template_id() {
|
204 |
+
register_post_meta(
|
205 |
+
'',
|
206 |
+
'_wp_template_id',
|
207 |
+
array(
|
208 |
+
'auth_callback' => array( $this, 'meta_template_id_auth_callback' ),
|
209 |
+
'show_in_rest' => true,
|
210 |
+
'single' => true,
|
211 |
+
'type' => 'integer',
|
212 |
+
)
|
213 |
+
);
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Auth callback.
|
218 |
+
*
|
219 |
+
* @return mixed
|
220 |
+
*/
|
221 |
+
public function meta_template_id_auth_callback() {
|
222 |
+
return current_user_can( 'edit_theme_options' );
|
223 |
+
}
|
224 |
+
|
225 |
+
/**
|
226 |
+
* Enqueue assets.
|
227 |
+
*/
|
228 |
+
public function enqueue_script_and_style() {
|
229 |
+
$script_dependencies = json_decode(
|
230 |
+
file_get_contents(
|
231 |
+
plugin_dir_path( __FILE__ ) . 'dist/full-site-editing.deps.json'
|
232 |
+
),
|
233 |
+
true
|
234 |
+
);
|
235 |
+
wp_enqueue_script(
|
236 |
+
'a8c-full-site-editing-script',
|
237 |
+
plugins_url( 'dist/full-site-editing.js', __FILE__ ),
|
238 |
+
is_array( $script_dependencies ) ? $script_dependencies : array(),
|
239 |
+
filemtime( plugin_dir_path( __FILE__ ) . 'dist/full-site-editing.js' ),
|
240 |
+
true
|
241 |
+
);
|
242 |
+
|
243 |
+
$feature_flags = A8C_Full_Site_Editing_Feature_Flags::get_instance();
|
244 |
+
|
245 |
+
wp_localize_script(
|
246 |
+
'a8c-full-site-editing-script',
|
247 |
+
'fullSiteEditing',
|
248 |
+
array(
|
249 |
+
'editorPostType' => get_current_screen()->post_type,
|
250 |
+
'featureFlags' => $feature_flags->get_flags(),
|
251 |
+
)
|
252 |
+
);
|
253 |
+
|
254 |
+
$style_file = is_rtl()
|
255 |
+
? 'full-site-editing.rtl.css'
|
256 |
+
: 'full-site-editing.css';
|
257 |
+
wp_enqueue_style(
|
258 |
+
'a8c-full-site-editing-style',
|
259 |
+
plugins_url( 'dist/' . $style_file, __FILE__ ),
|
260 |
+
array(),
|
261 |
+
filemtime( plugin_dir_path( __FILE__ ) . 'dist/' . $style_file )
|
262 |
+
);
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Register blocks.
|
267 |
+
*/
|
268 |
+
public function register_blocks() {
|
269 |
+
register_block_type(
|
270 |
+
'a8c/post-content',
|
271 |
+
array(
|
272 |
+
'render_callback' => 'render_post_content_block',
|
273 |
+
)
|
274 |
+
);
|
275 |
+
|
276 |
+
register_block_type(
|
277 |
+
'a8c/template',
|
278 |
+
array(
|
279 |
+
'render_callback' => 'render_template_block',
|
280 |
+
)
|
281 |
+
);
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* This will set the `wp_template` and `wp_template_part` post types to `public` to support
|
286 |
+
* the core search endpoint, which looks for it.
|
287 |
+
*/
|
288 |
+
public function allow_searching_for_templates() {
|
289 |
+
$post_type = get_post_type_object( 'wp_template' );
|
290 |
+
if ( ! ( $post_type instanceof WP_Post_Type ) ) {
|
291 |
+
return;
|
292 |
+
}
|
293 |
+
|
294 |
+
// Setting this to `public` will allow it to be found in the search endpoint.
|
295 |
+
$post_type->public = true;
|
296 |
+
|
297 |
+
$post_type = get_post_type_object( 'wp_template_part' );
|
298 |
+
if ( ! ( $post_type instanceof WP_Post_Type ) ) {
|
299 |
+
return;
|
300 |
+
}
|
301 |
+
|
302 |
+
// Setting this to `public` will allow it to be found in the search endpoint.
|
303 |
+
$post_type->public = true;
|
304 |
+
}
|
305 |
+
}
|
full-site-editing/components/post-autocomplete/index.js
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* eslint-disable wpcalypso/jsx-classname-namespace */
|
2 |
+
/**
|
3 |
+
* External dependencies
|
4 |
+
*/
|
5 |
+
import { debounce, map } from 'lodash';
|
6 |
+
|
7 |
+
/**
|
8 |
+
* WordPress dependencies
|
9 |
+
*/
|
10 |
+
import apiFetch from '@wordpress/api-fetch';
|
11 |
+
import { Button, Popover, Spinner, TextControl } from '@wordpress/components';
|
12 |
+
import { withState } from '@wordpress/compose';
|
13 |
+
import { useState } from '@wordpress/element';
|
14 |
+
import { __ } from '@wordpress/i18n';
|
15 |
+
import { addQueryArgs } from '@wordpress/url';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Internal dependencies
|
19 |
+
*/
|
20 |
+
import './style.scss';
|
21 |
+
|
22 |
+
const updateSuggestions = debounce( async ( search, postType, setState ) => {
|
23 |
+
setState( {
|
24 |
+
loading: true,
|
25 |
+
showSuggestions: true,
|
26 |
+
suggestions: [],
|
27 |
+
} );
|
28 |
+
|
29 |
+
const suggestions = await apiFetch( {
|
30 |
+
path: addQueryArgs( '/wp/v2/search', {
|
31 |
+
context: 'embed',
|
32 |
+
per_page: 20,
|
33 |
+
search,
|
34 |
+
...( !! postType && { subtype: postType } ),
|
35 |
+
} ),
|
36 |
+
} );
|
37 |
+
|
38 |
+
setState( {
|
39 |
+
loading: false,
|
40 |
+
showSuggestions: true,
|
41 |
+
suggestions,
|
42 |
+
} );
|
43 |
+
}, 200 );
|
44 |
+
|
45 |
+
const selectSuggestion = ( { id, title, subtype: type }, setState, setSearch ) => {
|
46 |
+
setState( {
|
47 |
+
loading: false,
|
48 |
+
showSuggestions: false,
|
49 |
+
suggestions: [],
|
50 |
+
} );
|
51 |
+
setSearch( title );
|
52 |
+
|
53 |
+
return { id, type };
|
54 |
+
};
|
55 |
+
|
56 |
+
/**
|
57 |
+
* External props:
|
58 |
+
* @param {Function} onSelectPost Callback invoked when a post is selected, returning its object.
|
59 |
+
* @param {?string|Array} postType If set, limits the search to the given post type, or array of post types.
|
60 |
+
* @param {?string} initialValue If set, is the initial value of the input field.
|
61 |
+
*/
|
62 |
+
const PostAutocomplete = withState( {
|
63 |
+
loading: false,
|
64 |
+
showSuggestions: false,
|
65 |
+
suggestions: [],
|
66 |
+
} )(
|
67 |
+
( { initialValue, loading, onSelectPost, postType, setState, showSuggestions, suggestions } ) => {
|
68 |
+
const [ search, setSearch ] = useState( initialValue );
|
69 |
+
|
70 |
+
const onChange = inputValue => {
|
71 |
+
setSearch( inputValue );
|
72 |
+
if ( inputValue.length < 2 ) {
|
73 |
+
setState( {
|
74 |
+
loading: false,
|
75 |
+
showSuggestions: false,
|
76 |
+
} );
|
77 |
+
return;
|
78 |
+
}
|
79 |
+
updateSuggestions( inputValue, postType, setState );
|
80 |
+
};
|
81 |
+
|
82 |
+
const onClick = suggestion => () => {
|
83 |
+
const selectedPost = selectSuggestion( suggestion, setState, setSearch );
|
84 |
+
onSelectPost( selectedPost );
|
85 |
+
};
|
86 |
+
|
87 |
+
return (
|
88 |
+
<div className="a8c-post-autocomplete">
|
89 |
+
<TextControl
|
90 |
+
autoComplete="off"
|
91 |
+
onChange={ onChange }
|
92 |
+
placeholder={ __( 'Type to search' ) }
|
93 |
+
type="search"
|
94 |
+
value={ search }
|
95 |
+
/>
|
96 |
+
{ loading && <Spinner /> }
|
97 |
+
{ showSuggestions && !! suggestions.length && (
|
98 |
+
<Popover focusOnMount={ false } noArrow position="bottom">
|
99 |
+
<div className="a8c-post-autocomplete__suggestions">
|
100 |
+
{ map( suggestions, suggestion => (
|
101 |
+
<Button isLarge isLink key={ suggestion.id } onClick={ onClick( suggestion ) }>
|
102 |
+
{ suggestion.title }
|
103 |
+
</Button>
|
104 |
+
) ) }
|
105 |
+
</div>
|
106 |
+
</Popover>
|
107 |
+
) }
|
108 |
+
</div>
|
109 |
+
);
|
110 |
+
}
|
111 |
+
);
|
112 |
+
|
113 |
+
export default PostAutocomplete;
|
full-site-editing/components/post-autocomplete/style.scss
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.a8c-post-autocomplete {
|
2 |
+
position: relative;
|
3 |
+
|
4 |
+
.components-spinner {
|
5 |
+
bottom: 7px;
|
6 |
+
position: absolute;
|
7 |
+
right: -5px;
|
8 |
+
}
|
9 |
+
}
|
10 |
+
|
11 |
+
.a8c-post-autocomplete__suggestions {
|
12 |
+
max-height: 200px;
|
13 |
+
overflow-y: auto;
|
14 |
+
width: 302px;
|
15 |
+
|
16 |
+
.components-button {
|
17 |
+
display: block;
|
18 |
+
height: auto;
|
19 |
+
min-height: 30px;
|
20 |
+
white-space: normal;
|
21 |
+
width: 100%;
|
22 |
+
word-wrap: break-word;
|
23 |
+
}
|
24 |
+
}
|
full-site-editing/dist/full-site-editing.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.a8c-post-autocomplete{position:relative}.a8c-post-autocomplete .components-spinner{bottom:7px;position:absolute;right:-5px}.a8c-post-autocomplete__suggestions{max-height:200px;overflow-y:auto;width:302px}.a8c-post-autocomplete__suggestions .components-button{display:block;height:auto;min-height:30px;white-space:normal;width:100%;word-wrap:break-word}.post-content-block.alignfull{padding:0 12px}.post-content-block__selector{width:300px}.post-content-block__selector a{font-family:sans-serif;font-size:13px;padding-left:8px}.post-content-block__preview{pointer-events:none}.post-content-block__preview:after{content:"";clear:both;display:table}.template-block.alignfull{padding:0 12px}.template-block__selector{width:300px}.template-block__selector a{font-family:sans-serif;font-size:13px;padding-left:8px}.template-block__content{pointer-events:none}.template-block__content:after{content:"";clear:both;display:table}
|
full-site-editing/dist/full-site-editing.deps.json
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
["lodash","wp-api-fetch","wp-blocks","wp-components","wp-compose","wp-data","wp-edit-post","wp-editor","wp-element","wp-i18n","wp-plugins","wp-url"]
|
full-site-editing/dist/full-site-editing.js
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=26)}([function(e,t){e.exports=wp.element},function(e,t){e.exports=wp.i18n},function(e,t){e.exports=wp.components},function(e,t){e.exports=lodash},function(e,t){e.exports=wp.compose},function(e,t){e.exports=wp.data},function(e,t,n){var o;
|
2 |
+
/*!
|
3 |
+
Copyright (c) 2017 Jed Watson.
|
4 |
+
Licensed under the MIT License (MIT), see
|
5 |
+
http://jedwatson.github.io/classnames
|
6 |
+
*/
|
7 |
+
/*!
|
8 |
+
Copyright (c) 2017 Jed Watson.
|
9 |
+
Licensed under the MIT License (MIT), see
|
10 |
+
http://jedwatson.github.io/classnames
|
11 |
+
*/
|
12 |
+
!function(){"use strict";var n={}.hasOwnProperty;function r(){for(var e=[],t=0;t<arguments.length;t++){var o=arguments[t];if(o){var c=typeof o;if("string"===c||"number"===c)e.push(o);else if(Array.isArray(o)&&o.length){var i=r.apply(null,o);i&&e.push(i)}else if("object"===c)for(var a in o)n.call(o,a)&&o[a]&&e.push(a)}}return e.join(" ")}e.exports?(r.default=r,e.exports=r):void 0===(o=function(){return r}.apply(t,[]))||(e.exports=o)}()},function(e,t){e.exports=function(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}},function(e,t){e.exports=wp.blocks},function(e,t){e.exports=wp.editor},function(e,t){e.exports=wp.editPost},function(e,t,n){},function(e,t,n){var o=n(18),r=n(19),c=n(20);e.exports=function(e,t){return o(e)||r(e,t)||c()}},function(e,t,n){var o=n(7);e.exports=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),r.forEach(function(t){o(e,t,n[t])})}return e}},function(e,t){function n(e,t,n,o,r,c,i){try{var a=e[c](i),l=a.value}catch(s){return void n(s)}a.done?t(l):Promise.resolve(l).then(o,r)}e.exports=function(e){return function(){var t=this,o=arguments;return new Promise(function(r,c){var i=e.apply(t,o);function a(e){n(i,r,c,a,l,"next",e)}function l(e){n(i,r,c,a,l,"throw",e)}a(void 0)})}}},function(e,t){e.exports=wp.apiFetch},function(e,t){e.exports=wp.url},function(e,t){e.exports=wp.plugins},function(e,t){e.exports=function(e){if(Array.isArray(e))return e}},function(e,t){e.exports=function(e,t){var n=[],o=!0,r=!1,c=void 0;try{for(var i,a=e[Symbol.iterator]();!(o=(i=a.next()).done)&&(n.push(i.value),!t||n.length!==t);o=!0);}catch(l){r=!0,c=l}finally{try{o||null==a.return||a.return()}finally{if(r)throw c}}return n}},function(e,t){e.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}},function(e,t,n){},,function(e,t,n){},,,function(e,t,n){"use strict";n.r(t);var o=n(8),r=n(1),c=n(7),i=n.n(c),a=n(0),l=n(6),s=n.n(l),u=n(3),p=n(2),d=n(4),b=n(5),f=n(9),m=n(12),g=n.n(m),O=n(13),j=n.n(O),y=n(14),v=n.n(y),_=n(15),h=n.n(_),w=n(16),E=(n(21),Object(u.debounce)(function(){var e=v()(regeneratorRuntime.mark(function e(t,n,o){var r;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return o({loading:!0,showSuggestions:!0,suggestions:[]}),e.next=3,h()({path:Object(w.addQueryArgs)("/wp/v2/search",j()({context:"embed",per_page:20,search:t},!!n&&{subtype:n}))});case 3:r=e.sent,o({loading:!1,showSuggestions:!0,suggestions:r});case 5:case"end":return e.stop()}},e)}));return function(t,n,o){return e.apply(this,arguments)}}(),200)),P=Object(d.withState)({loading:!1,showSuggestions:!1,suggestions:[]})(function(e){var t=e.initialValue,n=e.loading,o=e.onSelectPost,c=e.postType,i=e.setState,l=e.showSuggestions,s=e.suggestions,d=Object(a.useState)(t),b=g()(d,2),f=b[0],m=b[1],O=function(e){return function(){var t=function(e,t,n){var o=e.id,r=e.title,c=e.subtype;return t({loading:!1,showSuggestions:!1,suggestions:[]}),n(r),{id:o,type:c}}(e,i,m);o(t)}};return Object(a.createElement)("div",{className:"a8c-post-autocomplete"},Object(a.createElement)(p.TextControl,{autoComplete:"off",onChange:function(e){m(e),e.length<2?i({loading:!1,showSuggestions:!1}):E(e,c,i)},placeholder:Object(r.__)("Type to search"),type:"search",value:f}),n&&Object(a.createElement)(p.Spinner,null),l&&!!s.length&&Object(a.createElement)(p.Popover,{focusOnMount:!1,noArrow:!0,position:"bottom"},Object(a.createElement)("div",{className:"a8c-post-autocomplete__suggestions"},Object(u.map)(s,function(e){return Object(a.createElement)(p.Button,{isLarge:!0,isLink:!0,key:e.id,onClick:O(e)},e.title)}))))}),S=Object(d.compose)(Object(d.withState)({isEditing:!1,selectedPostId:void 0,selectedPostType:void 0}),Object(b.withSelect)(function(e,t){var n=t.selectedPostId,o=t.selectedPostType;return{selectedPost:(0,e("core").getEntityRecord)("postType",o,n)}}))(function(e){var t=e.attributes,n=e.isEditing,o=e.selectedPost,c=e.setState,l=t.align,d=!n||!!o,b=n||!o,m=!n&&!!o;return Object(a.createElement)(a.Fragment,null,d&&Object(a.createElement)(f.BlockControls,null,Object(a.createElement)(p.Toolbar,null,Object(a.createElement)(p.IconButton,{className:s()("components-icon-button components-toolbar__control",{"is-active":n}),label:Object(r.__)("Change Preview"),onClick:function(){return c({isEditing:!n})},icon:"edit"}))),Object(a.createElement)("div",{className:s()("post-content-block",i()({},"align".concat(l),l))},b&&Object(a.createElement)(p.Placeholder,{icon:"layout",label:Object(r.__)("Content Slot"),instructions:Object(r.__)("Placeholder for a post or a page.")},Object(a.createElement)("div",{className:"post-content-block__selector"},Object(a.createElement)("div",null,Object(r.__)("Select something to preview:")),Object(a.createElement)(P,{initialValue:Object(u.get)(o,["title","rendered"]),onSelectPost:function(e){var t=e.id,n=e.type;c({isEditing:!1,selectedPostId:t,selectedPostType:n})},postType:["page","post"]}),!!o&&Object(a.createElement)("a",{href:"?post=".concat(o.id,"&action=edit")},Object(r.sprintf)(Object(r.__)('Edit "%s"'),Object(u.get)(o,["title","rendered"],""))))),m&&Object(a.createElement)(a.RawHTML,{className:"post-content-block__preview"},Object(u.get)(o,["content","rendered"]))))});n(23);"wp_template"===fullSiteEditing.editorPostType&&Object(o.registerBlockType)("a8c/post-content",{title:Object(r.__)("Content Slot"),description:Object(r.__)("Placeholder for a post or a page."),icon:"layout",category:"layout",supports:{align:["wide","full"],anchor:!0,html:!1,multiple:!1,reusable:!1},edit:S,save:function(){return null}});n(11);var x=Object(d.compose)(Object(b.withSelect)(function(e,t){var n=t.attributes,o=e("core").getEntityRecord,r=n.templateId;return{template:r&&o("postType","wp_template_part",r)}}),Object(d.withState)({isEditing:!1}))(function(e){var t=e.attributes,n=e.isEditing,o=e.template,c=e.setAttributes,l=e.setState,d=t.align,b=t.templateId,m=!n||!!b,g=n||!b,O=!n&&!!b;return Object(a.createElement)(a.Fragment,null,m&&Object(a.createElement)(f.BlockControls,null,Object(a.createElement)(p.Toolbar,null,Object(a.createElement)(p.IconButton,{className:s()("components-icon-button components-toolbar__control",{"is-active":n}),label:Object(r.__)("Change Template Part"),onClick:function(){return l({isEditing:!n})},icon:"edit"}))),Object(a.createElement)("div",{className:s()("template-block",i()({},"align".concat(d),d))},g&&Object(a.createElement)(p.Placeholder,{icon:"layout",label:Object(r.__)("Template Part"),instructions:Object(r.__)("Select a template part to display")},Object(a.createElement)("div",{className:"template-block__selector"},Object(a.createElement)(P,{initialValue:Object(u.get)(o,["title","rendered"]),onSelectPost:function(e){var t=e.id;l({isEditing:!1}),c({templateId:t})},postType:"wp_template_part"}),!!o&&Object(a.createElement)("a",{href:"?post=".concat(b,"&action=edit")},Object(r.sprintf)(Object(r.__)('Edit "%s"'),Object(u.get)(o,["title","rendered"],""))))),O&&Object(a.createElement)(a.RawHTML,{className:"template-block__content"},Object(u.get)(o,["content","rendered"]))))});"wp_template"===fullSiteEditing.editorPostType&&Object(o.registerBlockType)("a8c/template",{title:Object(r.__)("Template Part"),description:Object(r.__)("Display a template part."),icon:"layout",category:"layout",attributes:{templateId:{type:"number"}},supports:{align:["wide","full"],anchor:!0,html:!1,reusable:!1},edit:x,save:function(){return null}});var T=n(10),k=n(17),I=Object(d.compose)(Object(b.withDispatch)(function(e){return{setTemplateId:function(t){return e("core/editor").editPost({meta:{_wp_template_id:t}})}}}),Object(b.withSelect)(function(e){var t=e("core"),n=t.canUser,o=t.getEntityRecord,r=Object(u.get)(e("core/editor").getEditedPostAttribute("meta"),"_wp_template_id");return{canUserUpdateSettings:n("update","settings"),selectedTemplate:r&&o("postType","wp_template",r)}}))(function(e){var t=e.canUserUpdateSettings,n=e.setTemplateId,o=e.selectedTemplate;if(!t)return null;return Object(a.createElement)(a.Fragment,null,Object(a.createElement)(T.PluginSidebarMoreMenuItem,{target:"fse-template-sidebar",icon:"layout"},Object(r.__)("Template")),Object(a.createElement)(T.PluginSidebar,{icon:"layout",name:"fse-template-sidebar",title:Object(r.__)("Template")},Object(a.createElement)(p.PanelBody,null,Object(r.__)("Select a template"),Object(a.createElement)(P,{initialValue:Object(u.get)(o,["title","rendered"]),onSelectPost:function(e){var t=e.id;n(parseInt(t,10))},postType:"wp_template"}))))});"page"===fullSiteEditing.editorPostType&&Object(k.registerPlugin)("fse-template-selector-sidebar",{render:I})}]));
|
full-site-editing/dist/full-site-editing.rtl.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.a8c-post-autocomplete{position:relative}.a8c-post-autocomplete .components-spinner{bottom:7px;position:absolute;left:-5px}.a8c-post-autocomplete__suggestions{max-height:200px;overflow-y:auto;width:302px}.a8c-post-autocomplete__suggestions .components-button{display:block;height:auto;min-height:30px;white-space:normal;width:100%;word-wrap:break-word}.post-content-block.alignfull{padding:0 12px}.post-content-block__selector{width:300px}.post-content-block__selector a{font-family:sans-serif;font-size:13px;padding-right:8px}.post-content-block__preview{pointer-events:none}.post-content-block__preview:after{content:"";clear:both;display:table}.template-block.alignfull{padding:0 12px}.template-block__selector{width:300px}.template-block__selector a{font-family:sans-serif;font-size:13px;padding-right:8px}.template-block__content{pointer-events:none}.template-block__content:after{content:"";clear:both;display:table}
|
full-site-editing/index.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Internal dependencies
|
3 |
+
*/
|
4 |
+
import './blocks/post-content';
|
5 |
+
import './blocks/template';
|
6 |
+
import './plugins/template-selector-sidebar';
|
full-site-editing/plugins/template-selector-sidebar/index.js
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global fullSiteEditing */
|
2 |
+
/**
|
3 |
+
* External dependencies
|
4 |
+
*/
|
5 |
+
import { get } from 'lodash';
|
6 |
+
|
7 |
+
/**
|
8 |
+
* WordPress dependencies
|
9 |
+
*/
|
10 |
+
import { PanelBody } from '@wordpress/components';
|
11 |
+
import { compose } from '@wordpress/compose';
|
12 |
+
import { withDispatch, withSelect } from '@wordpress/data';
|
13 |
+
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-post';
|
14 |
+
import { Fragment } from '@wordpress/element';
|
15 |
+
import { __ } from '@wordpress/i18n';
|
16 |
+
import { registerPlugin } from '@wordpress/plugins';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Internal dependencies
|
20 |
+
*/
|
21 |
+
import PostAutocomplete from '../../components/post-autocomplete';
|
22 |
+
|
23 |
+
const TemplateSelectorSidebar = compose(
|
24 |
+
withDispatch( dispatch => ( {
|
25 |
+
setTemplateId: templateId =>
|
26 |
+
dispatch( 'core/editor' ).editPost( { meta: { _wp_template_id: templateId } } ),
|
27 |
+
} ) ),
|
28 |
+
withSelect( select => {
|
29 |
+
const { canUser, getEntityRecord } = select( 'core' );
|
30 |
+
const templateId = get(
|
31 |
+
select( 'core/editor' ).getEditedPostAttribute( 'meta' ),
|
32 |
+
'_wp_template_id'
|
33 |
+
);
|
34 |
+
return {
|
35 |
+
canUserUpdateSettings: canUser( 'update', 'settings' ),
|
36 |
+
selectedTemplate: templateId && getEntityRecord( 'postType', 'wp_template', templateId ),
|
37 |
+
};
|
38 |
+
} )
|
39 |
+
)( ( { canUserUpdateSettings, setTemplateId, selectedTemplate } ) => {
|
40 |
+
if ( ! canUserUpdateSettings ) {
|
41 |
+
return null;
|
42 |
+
}
|
43 |
+
|
44 |
+
const onSelectTemplate = ( { id } ) => {
|
45 |
+
setTemplateId( parseInt( id, 10 ) );
|
46 |
+
};
|
47 |
+
|
48 |
+
return (
|
49 |
+
<Fragment>
|
50 |
+
<PluginSidebarMoreMenuItem target="fse-template-sidebar" icon="layout">
|
51 |
+
{ __( 'Template' ) }
|
52 |
+
</PluginSidebarMoreMenuItem>
|
53 |
+
<PluginSidebar icon="layout" name="fse-template-sidebar" title={ __( 'Template' ) }>
|
54 |
+
<PanelBody>
|
55 |
+
{ __( 'Select a template' ) }
|
56 |
+
<PostAutocomplete
|
57 |
+
initialValue={ get( selectedTemplate, [ 'title', 'rendered' ] ) }
|
58 |
+
onSelectPost={ onSelectTemplate }
|
59 |
+
postType="wp_template"
|
60 |
+
/>
|
61 |
+
</PanelBody>
|
62 |
+
</PluginSidebar>
|
63 |
+
</Fragment>
|
64 |
+
);
|
65 |
+
} );
|
66 |
+
|
67 |
+
if ( 'page' === fullSiteEditing.editorPostType ) {
|
68 |
+
registerPlugin( 'fse-template-selector-sidebar', {
|
69 |
+
render: TemplateSelectorSidebar,
|
70 |
+
} );
|
71 |
+
}
|
lib/feature-flags/feature-flags.php
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Feature flags file.
|
4 |
+
*
|
5 |
+
* @package full-site-editing
|
6 |
+
*/
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class A8C_Full_Site_Editing_Feature_Flags
|
10 |
+
*/
|
11 |
+
class A8C_Full_Site_Editing_Feature_Flags {
|
12 |
+
/**
|
13 |
+
* Class instance.
|
14 |
+
*
|
15 |
+
* @var A8C_Full_Site_Editing_Feature_Flags
|
16 |
+
*/
|
17 |
+
private static $instance = null;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Feature flags.
|
21 |
+
*
|
22 |
+
* @var array
|
23 |
+
*/
|
24 |
+
private $flags = [];
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Parameter and cookie name for storing/retrieving the feature flags.
|
28 |
+
*
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
const FEATURE_FLAGS = 'fse_feature_flags';
|
32 |
+
|
33 |
+
/**
|
34 |
+
* A8C_Full_Site_Editing_Feature_Flags constructor.
|
35 |
+
*/
|
36 |
+
private function __construct() {
|
37 |
+
$this->set_flags();
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Creates instance.
|
42 |
+
*
|
43 |
+
* @return A8C_Full_Site_Editing_Feature_Flags
|
44 |
+
*/
|
45 |
+
public static function get_instance() {
|
46 |
+
if ( is_null( self::$instance ) ) {
|
47 |
+
self::$instance = new self();
|
48 |
+
}
|
49 |
+
|
50 |
+
return self::$instance;
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Get the feature flags.
|
55 |
+
*
|
56 |
+
* @return array
|
57 |
+
*/
|
58 |
+
public function get_flags() {
|
59 |
+
return $this->flags;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Check if a feature flag is enabled.
|
64 |
+
*
|
65 |
+
* @param string $flag_name Feature flag.
|
66 |
+
* @return boolean
|
67 |
+
*/
|
68 |
+
public function is_enabled( $flag_name ) {
|
69 |
+
if ( ! isset( $flag_name, $this->flags[ $flag_name ] ) ) {
|
70 |
+
return false;
|
71 |
+
}
|
72 |
+
|
73 |
+
return (boolean) $this->flags[ $flag_name ];
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Set the feature flags based on GET parameter or cookie value.
|
78 |
+
*/
|
79 |
+
private function set_flags() {
|
80 |
+
$flags = null;
|
81 |
+
|
82 |
+
$has_flags_param = isset( $_GET[ self::FEATURE_FLAGS ] );
|
83 |
+
$has_flags_cookie = isset( $_COOKIE[ self::FEATURE_FLAGS ] );
|
84 |
+
|
85 |
+
// Remove all of the flag values when empty parameter is passed.
|
86 |
+
if ( $has_flags_param && empty( $_GET[ self::FEATURE_FLAGS ] ) ) {
|
87 |
+
setcookie( self::FEATURE_FLAGS, '', time() - 3600 );
|
88 |
+
$this->flags = [];
|
89 |
+
return;
|
90 |
+
}
|
91 |
+
|
92 |
+
if ( $has_flags_param ) {
|
93 |
+
setcookie( self::FEATURE_FLAGS, $_GET[ self::FEATURE_FLAGS ] );
|
94 |
+
$flags = $_GET[ self::FEATURE_FLAGS ];
|
95 |
+
} else if ( $has_flags_cookie ) {
|
96 |
+
$flags = $_COOKIE[ self::FEATURE_FLAGS ];
|
97 |
+
}
|
98 |
+
|
99 |
+
if ( empty( $flags ) ) {
|
100 |
+
$this->flags = [];
|
101 |
+
return;
|
102 |
+
}
|
103 |
+
|
104 |
+
// Feature flags are represented as a string of comma-separated feature flag names.
|
105 |
+
// For example: "flag1,flag2,-flag3" (leading "-" denotes that the given flag is disabled).
|
106 |
+
foreach ( explode( ',', $flags ) as $flag ) {
|
107 |
+
$flag = trim( $flag );
|
108 |
+
$is_enabled = '-' !== $flag[0];
|
109 |
+
|
110 |
+
// Strip "-" for disabled flags to obtain the correct name
|
111 |
+
$name = $is_enabled ? $flag : substr( $flag, 1 );
|
112 |
+
|
113 |
+
$this->flags[ $name ] = $is_enabled;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
}
|
lib/feature-flags/index.js
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* global fullSiteEditing */
|
2 |
+
/**
|
3 |
+
* External dependencies
|
4 |
+
*/
|
5 |
+
import { get } from 'lodash';
|
6 |
+
|
7 |
+
const isEnabled = flag => get( fullSiteEditing, [ 'featureFlags', flag ], false );
|
8 |
+
|
9 |
+
export default isEnabled;
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: automattic, get_dave, marekhrabe, mppfeiffer, obenland
|
|
3 |
Tags: block, blocks, editor, gutenberg, page
|
4 |
Requires at least: 5.0
|
5 |
Tested up to: 5.2
|
6 |
-
Stable tag: 0.1
|
7 |
Requires PHP: 5.6.20
|
8 |
License: GPLv2 or later
|
9 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
@@ -40,5 +40,8 @@ This plugin is experimental, so we don't provide any support for it outside of w
|
|
40 |
|
41 |
== Changelog ==
|
42 |
|
|
|
|
|
|
|
43 |
= 0.1 =
|
44 |
* Initial Release
|
3 |
Tags: block, blocks, editor, gutenberg, page
|
4 |
Requires at least: 5.0
|
5 |
Tested up to: 5.2
|
6 |
+
Stable tag: 0.1.1
|
7 |
Requires PHP: 5.6.20
|
8 |
License: GPLv2 or later
|
9 |
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
40 |
|
41 |
== Changelog ==
|
42 |
|
43 |
+
= 0.1.1 =
|
44 |
+
* Latest round of updates
|
45 |
+
|
46 |
= 0.1 =
|
47 |
* Initial Release
|
starter-page-templates/class-starter-page-templates.php
CHANGED
@@ -76,6 +76,7 @@ class Starter_Page_Templates {
|
|
76 |
}
|
77 |
|
78 |
wp_enqueue_script( 'starter-page-templates' );
|
|
|
79 |
|
80 |
$default_info = array(
|
81 |
'title' => get_bloginfo( 'name' ),
|
76 |
}
|
77 |
|
78 |
wp_enqueue_script( 'starter-page-templates' );
|
79 |
+
wp_set_script_translations( 'starter-page-templates', 'full-site-editing' );
|
80 |
|
81 |
$default_info = array(
|
82 |
'title' => get_bloginfo( 'name' ),
|
starter-page-templates/dist/starter-page-templates.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.page-template-modal{width:100%;height:100vh}@media screen and (min-width:783px){.page-template-modal{width:calc(100% - 65px);left:50px;transform:translateY(-50%)}}@media screen and (min-width:960px){.page-template-modal{width:calc(100% - 200px);left:180px}}.page-template-modal .components-modal__header-heading-container{justify-content:center}.page-template-modal__inner{max-width:700px;margin:0 auto;padding:1em 0 3em}.page-template-modal__intro{text-align:center}.page-template-modal__list{padding:1.5em 0}.page-template-modal__list .components-base-
|
1 |
+
.page-template-modal{width:100%;height:100vh}@media screen and (min-width:783px){body:not(.is-fullscreen-mode) .page-template-modal{width:calc(100% - 65px);left:50px;transform:translateY(-50%)}}@media screen and (min-width:960px){body:not(.is-fullscreen-mode) .page-template-modal{width:calc(100% - 200px);left:180px}}.page-template-modal .components-modal__header-heading-container{justify-content:center}.page-template-modal__inner{max-width:700px;margin:0 auto;padding:1em 0 3em}.page-template-modal__intro{text-align:center}.page-template-modal__list{padding:1.5em 0}.page-template-modal__list .components-base-control__label{border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.page-template-modal__list .template-selector-control__options{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));grid-gap:1.5em}.page-template-modal__list .template-selector-control__label{display:block;width:100%;text-align:center;border:1px solid transparent;padding:2em;border-radius:4px;cursor:pointer}.page-template-modal__list .template-selector-control__label:hover{background:#f3f4f5}.page-template-modal__list .template-selector-control__label:focus{box-shadow:0 0 0 2px #00a0d2;outline:2px solid transparent;outline-offset:-2px}.page-template-modal__list .template-selector-control__media-wrap{width:100%;display:block;margin:0 auto 2em;border:1px solid rgba(25,30,35,.2);background:#f6f6f6;border-radius:4px;overflow:hidden;padding-bottom:90%;box-sizing:content-box;position:relative;pointer-events:none}.page-template-modal__list .template-selector-control__media{width:100%;display:block;position:absolute;top:0;left:0}.page-template-modal__actions{display:flex;flex-direction:column;align-items:center}@media screen and (min-width:960px){.page-template-modal__actions{flex-direction:row;justify-content:flex-end}}@media screen and (max-width:960px){.page-template-modal__action{margin-bottom:1em}}@media screen and (min-width:960px){.page-template-modal__action-use{margin-right:1em}}
|
starter-page-templates/dist/starter-page-templates.deps.json
CHANGED
@@ -1 +1 @@
|
|
1 |
-
["lodash","wp-components","wp-compose","wp-element"]
|
1 |
+
["lodash","wp-blocks","wp-components","wp-compose","wp-data","wp-element","wp-i18n","wp-plugins"]
|
starter-page-templates/dist/starter-page-templates.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=
|
2 |
/*!
|
3 |
Copyright (c) 2017 Jed Watson.
|
4 |
Licensed under the MIT License (MIT), see
|
@@ -9,4 +9,4 @@
|
|
9 |
Licensed under the MIT License (MIT), see
|
10 |
http://jedwatson.github.io/classnames
|
11 |
*/
|
12 |
-
!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var
|
1 |
+
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=11)}([function(e,t){e.exports=wp.element},function(e,t){e.exports=wp.i18n},function(e,t){e.exports=lodash},function(e,t){e.exports=wp.compose},function(e,t){e.exports=wp.components},function(e,t){e.exports=wp.plugins},function(e,t){e.exports=wp.data},function(e,t){e.exports=wp.blocks},function(e,t,n){var r;
|
2 |
/*!
|
3 |
Copyright (c) 2017 Jed Watson.
|
4 |
Licensed under the MIT License (MIT), see
|
9 |
Licensed under the MIT License (MIT), see
|
10 |
http://jedwatson.github.io/classnames
|
11 |
*/
|
12 |
+
!function(){"use strict";var n={}.hasOwnProperty;function a(){for(var e=[],t=0;t<arguments.length;t++){var r=arguments[t];if(r){var l=typeof r;if("string"===l||"number"===l)e.push(r);else if(Array.isArray(r)&&r.length){var o=a.apply(null,r);o&&e.push(o)}else if("object"===l)for(var c in r)n.call(r,c)&&r[c]&&e.push(c)}}return e.join(" ")}e.exports?(a.default=a,e.exports=a):void 0===(r=function(){return a}.apply(t,[]))||(e.exports=r)}()},function(e,t,n){},,function(e,t,n){"use strict";n.r(t);var r=n(0),a=n(2),l=n(1),o=n(3),c=n(4),i=n(5),s=n(6),p=n(7),u={Address:Object(l._x)("123 Main St","default address","full-site-editing"),Phone:Object(l._x)("555-555-5555","default phone number","full-site-editing"),CompanyName:Object(l._x)("Your Company Name","default company name","full-site-editing"),Vertical:Object(l._x)("Business","default vertical name","full-site-editing")},m={CompanyName:"title",Address:"address",Phone:"phone",Vertical:"vertical"},f=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.replace(/{{(\w+)}}/g,function(e,n){var r=u[n];return t[m[n]]||r||n})},d=(n(9),n(8)),b=n.n(d);var g=Object(o.withInstanceId)(function(e){var t=e.label,n=e.className,l=e.help,o=e.instanceId,i=e.onClick,s=e.templates,p=void 0===s?[]:s,u="inspector-radio-control-".concat(o),m=function(e){return i(e.target.value)};return Object(a.isEmpty)(p)?null:Object(r.createElement)(c.BaseControl,{label:t,id:u,help:l,className:b()(n,"template-selector-control")},Object(r.createElement)("ul",{className:"template-selector-control__options"},p.map(function(e,t){return Object(r.createElement)("li",{key:"".concat(u,"-").concat(t),className:"template-selector-control__option"},Object(r.createElement)("button",{type:"button",id:"".concat(u,"-").concat(t),className:"template-selector-control__label",value:e.value,onClick:m,"aria-describedby":l?"".concat(u,"__help"):void 0},Object(r.createElement)("div",{className:"template-selector-control__media-wrap"},e.preview&&Object(r.createElement)("img",{className:"template-selector-control__media",src:e.preview,alt:e.previewAlt||""})),e.label))})))});if(window.starterPageTemplatesConfig){var v={home:{src:"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-home-2.png",alt:"Full width hero banner, followed by alternating text and image sections, followed by a Get in Touch area"},menu:{src:"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-menu-2.png",alt:""},"contact-us":{src:"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-contactus-2.png",alt:""}};window.starterPageTemplatesConfig.templates=Object(a.map)(window.starterPageTemplatesConfig.templates,function(e){return e.preview=v[e.slug],e})}var O=window.starterPageTemplatesConfig,j=O.siteInformation,w=void 0===j?{}:j,_=O.templates,y=void 0===_?[]:_,h=Object(s.dispatch)("core/editor"),x=Object(o.withState)({isOpen:!0,isLoading:!1,verticalTemplates:Object(a.keyBy)(y,"slug")})(function(e){var t=e.isOpen,n=e.verticalTemplates,o=e.setState;return Object(r.createElement)("div",null,t&&Object(r.createElement)(c.Modal,{title:Object(l.__)("Select Page Template","full-site-editing"),onRequestClose:function(){return o({isOpen:!1})},className:"page-template-modal"},Object(r.createElement)("div",{className:"page-template-modal__inner"},Object(r.createElement)("form",{className:"page-template-modal__form"},Object(r.createElement)("fieldset",{className:"page-template-modal__list"},Object(r.createElement)("legend",{className:"page-template-modal__intro"},Object(r.createElement)("p",null,Object(l.__)("Pick a Template that matches the purpose of your page.","full-site-editing")),Object(r.createElement)("p",null,Object(l.__)("You can customize each Template to meet your needs.","full-site-editing"))),Object(r.createElement)(g,{label:Object(l.__)("Template","full-site-editing"),templates:Object.values(n).map(function(e){return{label:e.title,value:e.slug,preview:e.preview&&e.preview.src,previewAlt:e.preview&&e.preview.alt}}),onClick:function(e){o({isOpen:!1}),function(e){if(Object(a.has)(e,"content")){h.editPost({title:f(e.title,w)});var t=f(e.content,w),n=Object(p.parse)(t);h.insertBlocks(n)}}(n[e])}}))))))});Object(i.registerPlugin)("page-templates",{render:function(){return Object(r.createElement)(x,null)}})}]));
|
starter-page-templates/dist/starter-page-templates.rtl.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.page-template-modal{width:100%;height:100vh}@media screen and (min-width:783px){.page-template-modal{width:calc(100% - 65px);right:50px;transform:translateY(-50%)}}@media screen and (min-width:960px){.page-template-modal{width:calc(100% - 200px);right:180px}}.page-template-modal .components-modal__header-heading-container{justify-content:center}.page-template-modal__inner{max-width:700px;margin:0 auto;padding:1em 0 3em}.page-template-modal__intro{text-align:center}.page-template-modal__list{padding:1.5em 0}.page-template-modal__list .components-base-
|
1 |
+
.page-template-modal{width:100%;height:100vh}@media screen and (min-width:783px){body:not(.is-fullscreen-mode) .page-template-modal{width:calc(100% - 65px);right:50px;transform:translateY(-50%)}}@media screen and (min-width:960px){body:not(.is-fullscreen-mode) .page-template-modal{width:calc(100% - 200px);right:180px}}.page-template-modal .components-modal__header-heading-container{justify-content:center}.page-template-modal__inner{max-width:700px;margin:0 auto;padding:1em 0 3em}.page-template-modal__intro{text-align:center}.page-template-modal__list{padding:1.5em 0}.page-template-modal__list .components-base-control__label{border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;word-wrap:normal!important}.page-template-modal__list .template-selector-control__options{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));grid-gap:1.5em}.page-template-modal__list .template-selector-control__label{display:block;width:100%;text-align:center;border:1px solid transparent;padding:2em;border-radius:4px;cursor:pointer}.page-template-modal__list .template-selector-control__label:hover{background:#f3f4f5}.page-template-modal__list .template-selector-control__label:focus{box-shadow:0 0 0 2px #00a0d2;outline:2px solid transparent;outline-offset:-2px}.page-template-modal__list .template-selector-control__media-wrap{width:100%;display:block;margin:0 auto 2em;border:1px solid rgba(25,30,35,.2);background:#f6f6f6;border-radius:4px;overflow:hidden;padding-bottom:90%;box-sizing:content-box;position:relative;pointer-events:none}.page-template-modal__list .template-selector-control__media{width:100%;display:block;position:absolute;top:0;right:0}.page-template-modal__actions{display:flex;flex-direction:column;align-items:center}@media screen and (min-width:960px){.page-template-modal__actions{flex-direction:row;justify-content:flex-end}}@media screen and (max-width:960px){.page-template-modal__action{margin-bottom:1em}}@media screen and (min-width:960px){.page-template-modal__action-use{margin-left:1em}}
|
starter-page-templates/page-template-modal/components/template-selector-control.js
CHANGED
@@ -32,29 +32,31 @@ function TemplateSelectorControl( {
|
|
32 |
help={ help }
|
33 |
className={ classnames( className, 'template-selector-control' ) }
|
34 |
>
|
35 |
-
|
36 |
-
|
37 |
-
<
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
58 |
</BaseControl>
|
59 |
);
|
60 |
}
|
32 |
help={ help }
|
33 |
className={ classnames( className, 'template-selector-control' ) }
|
34 |
>
|
35 |
+
<ul className="template-selector-control__options">
|
36 |
+
{ templates.map( ( option, index ) => (
|
37 |
+
<li key={ `${ id }-${ index }` } className="template-selector-control__option">
|
38 |
+
<button
|
39 |
+
type="button"
|
40 |
+
id={ `${ id }-${ index }` }
|
41 |
+
className="template-selector-control__label"
|
42 |
+
value={ option.value }
|
43 |
+
onClick={ handleButtonClick }
|
44 |
+
aria-describedby={ help ? `${ id }__help` : undefined }
|
45 |
+
>
|
46 |
+
<div className="template-selector-control__media-wrap">
|
47 |
+
{ option.preview && (
|
48 |
+
<img
|
49 |
+
className="template-selector-control__media"
|
50 |
+
src={ option.preview }
|
51 |
+
alt={ option.previewAlt || '' }
|
52 |
+
/>
|
53 |
+
) }
|
54 |
+
</div>
|
55 |
+
{ option.label }
|
56 |
+
</button>
|
57 |
+
</li>
|
58 |
+
) ) }
|
59 |
+
</ul>
|
60 |
</BaseControl>
|
61 |
);
|
62 |
}
|
starter-page-templates/page-template-modal/index.js
CHANGED
@@ -1,18 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
/**
|
2 |
* Internal dependencies
|
3 |
*/
|
4 |
import replacePlaceholders from './utils/replace-placeholders';
|
5 |
import './styles/starter-page-templates-editor.scss';
|
6 |
import TemplateSelectorControl from './components/template-selector-control';
|
7 |
-
import { keyBy, map, has } from 'lodash';
|
8 |
|
9 |
// TODO: remove once we have proper previews from API
|
10 |
if ( window.starterPageTemplatesConfig ) {
|
11 |
const PREVIEWS_BY_SLUG = {
|
12 |
-
home:
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
};
|
17 |
window.starterPageTemplatesConfig.templates = map(
|
18 |
window.starterPageTemplatesConfig.templates,
|
@@ -23,71 +43,76 @@ if ( window.starterPageTemplatesConfig ) {
|
|
23 |
);
|
24 |
}
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
const { Modal } = wp.components;
|
29 |
-
const { withState } = wp.compose;
|
30 |
|
31 |
-
|
|
|
|
|
|
|
|
|
32 |
|
33 |
-
|
34 |
-
|
35 |
-
if ( ! has( template, 'content' ) ) {
|
36 |
-
return;
|
37 |
-
}
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
<div>
|
56 |
-
{ isOpen && (
|
57 |
-
<Modal
|
58 |
-
title="Select Page Template"
|
59 |
-
onRequestClose={ () => setState( { isOpen: false } ) }
|
60 |
-
className="page-template-modal"
|
61 |
-
>
|
62 |
-
<div className="page-template-modal__inner">
|
63 |
-
<div className="page-template-modal__intro">
|
64 |
-
<p>Pick a Template that matches the purpose of your page.</p>
|
65 |
-
<p>You can customise each Template to meet your needs.</p>
|
66 |
-
</div>
|
67 |
-
<form className="page-template-modal__form">
|
68 |
-
<fieldset className="page-template-modal__list">
|
69 |
-
<TemplateSelectorControl
|
70 |
-
label="Template"
|
71 |
-
templates={ Object.values( verticalTemplates ).map( template => ( {
|
72 |
-
label: template.title,
|
73 |
-
value: template.slug,
|
74 |
-
preview: template.preview,
|
75 |
-
} ) ) }
|
76 |
-
onClick={ newTemplate => {
|
77 |
-
setState( { isOpen: false } );
|
78 |
-
insertTemplate( verticalTemplates[ newTemplate ] );
|
79 |
-
} }
|
80 |
-
/>
|
81 |
-
</fieldset>
|
82 |
-
</form>
|
83 |
-
</div>
|
84 |
-
</Modal>
|
85 |
-
) }
|
86 |
-
</div>
|
87 |
-
) );
|
88 |
-
registerPlugin( 'page-templates', {
|
89 |
-
render: function() {
|
90 |
-
return <PageTemplateModal />;
|
91 |
-
},
|
92 |
-
} );
|
93 |
-
} )( window.wp, window.starterPageTemplatesConfig );
|
1 |
+
/**
|
2 |
+
* External dependencies
|
3 |
+
*/
|
4 |
+
import { keyBy, map, has } from 'lodash';
|
5 |
+
import { __ } from '@wordpress/i18n';
|
6 |
+
import { withState } from '@wordpress/compose';
|
7 |
+
import { Modal } from '@wordpress/components';
|
8 |
+
import { registerPlugin } from '@wordpress/plugins';
|
9 |
+
import { dispatch } from '@wordpress/data';
|
10 |
+
import { parse as parseBlocks } from '@wordpress/blocks';
|
11 |
+
|
12 |
/**
|
13 |
* Internal dependencies
|
14 |
*/
|
15 |
import replacePlaceholders from './utils/replace-placeholders';
|
16 |
import './styles/starter-page-templates-editor.scss';
|
17 |
import TemplateSelectorControl from './components/template-selector-control';
|
|
|
18 |
|
19 |
// TODO: remove once we have proper previews from API
|
20 |
if ( window.starterPageTemplatesConfig ) {
|
21 |
const PREVIEWS_BY_SLUG = {
|
22 |
+
home: {
|
23 |
+
src: 'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-home-2.png',
|
24 |
+
alt:
|
25 |
+
'Full width hero banner, followed by alternating text and image sections, followed by a Get in Touch area',
|
26 |
+
},
|
27 |
+
menu: {
|
28 |
+
src: 'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-menu-2.png',
|
29 |
+
alt: '',
|
30 |
+
},
|
31 |
+
'contact-us': {
|
32 |
+
src:
|
33 |
+
'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-contactus-2.png',
|
34 |
+
alt: '',
|
35 |
+
},
|
36 |
};
|
37 |
window.starterPageTemplatesConfig.templates = map(
|
38 |
window.starterPageTemplatesConfig.templates,
|
43 |
);
|
44 |
}
|
45 |
|
46 |
+
const { siteInformation = {}, templates = [] } = window.starterPageTemplatesConfig;
|
47 |
+
const editorDispatcher = dispatch( 'core/editor' );
|
|
|
|
|
48 |
|
49 |
+
const insertTemplate = template => {
|
50 |
+
// Skip inserting if there's nothing to insert.
|
51 |
+
if ( ! has( template, 'content' ) ) {
|
52 |
+
return;
|
53 |
+
}
|
54 |
|
55 |
+
// set title
|
56 |
+
editorDispatcher.editPost( { title: replacePlaceholders( template.title, siteInformation ) } );
|
|
|
|
|
|
|
57 |
|
58 |
+
// load content
|
59 |
+
const templateString = replacePlaceholders( template.content, siteInformation );
|
60 |
+
const blocks = parseBlocks( templateString );
|
61 |
+
editorDispatcher.insertBlocks( blocks );
|
62 |
+
};
|
63 |
|
64 |
+
const PageTemplateModal = withState( {
|
65 |
+
isOpen: true,
|
66 |
+
isLoading: false,
|
67 |
+
verticalTemplates: keyBy( templates, 'slug' ),
|
68 |
+
} )( ( { isOpen, verticalTemplates, setState } ) => (
|
69 |
+
<div>
|
70 |
+
{ isOpen && (
|
71 |
+
<Modal
|
72 |
+
title={ __( 'Select Page Template', 'full-site-editing' ) }
|
73 |
+
onRequestClose={ () => setState( { isOpen: false } ) }
|
74 |
+
className="page-template-modal"
|
75 |
+
>
|
76 |
+
<div className="page-template-modal__inner">
|
77 |
+
<form className="page-template-modal__form">
|
78 |
+
<fieldset className="page-template-modal__list">
|
79 |
+
<legend className="page-template-modal__intro">
|
80 |
+
<p>
|
81 |
+
{ __(
|
82 |
+
'Pick a Template that matches the purpose of your page.',
|
83 |
+
'full-site-editing'
|
84 |
+
) }
|
85 |
+
</p>
|
86 |
+
<p>
|
87 |
+
{ __(
|
88 |
+
'You can customize each Template to meet your needs.',
|
89 |
+
'full-site-editing'
|
90 |
+
) }
|
91 |
+
</p>
|
92 |
+
</legend>
|
93 |
+
<TemplateSelectorControl
|
94 |
+
label={ __( 'Template', 'full-site-editing' ) }
|
95 |
+
templates={ Object.values( verticalTemplates ).map( template => ( {
|
96 |
+
label: template.title,
|
97 |
+
value: template.slug,
|
98 |
+
preview: template.preview && template.preview.src,
|
99 |
+
previewAlt: template.preview && template.preview.alt,
|
100 |
+
} ) ) }
|
101 |
+
onClick={ newTemplate => {
|
102 |
+
setState( { isOpen: false } );
|
103 |
+
insertTemplate( verticalTemplates[ newTemplate ] );
|
104 |
+
} }
|
105 |
+
/>
|
106 |
+
</fieldset>
|
107 |
+
</form>
|
108 |
+
</div>
|
109 |
+
</Modal>
|
110 |
+
) }
|
111 |
+
</div>
|
112 |
+
) );
|
113 |
|
114 |
+
registerPlugin( 'page-templates', {
|
115 |
+
render: function() {
|
116 |
+
return <PageTemplateModal />;
|
117 |
+
},
|
118 |
+
} );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss
CHANGED
@@ -10,10 +10,16 @@
|
|
10 |
width: 1px;
|
11 |
word-wrap: normal !important;
|
12 |
}
|
|
|
|
|
13 |
.page-template-modal {
|
14 |
width: 100%;
|
15 |
height: 100vh;
|
|
|
16 |
|
|
|
|
|
|
|
17 |
@media screen and ( min-width: 783px ) {
|
18 |
width: calc( 100% - 65px );
|
19 |
left: 50px;
|
@@ -43,17 +49,18 @@
|
|
43 |
.page-template-modal__list {
|
44 |
padding: 1.5em 0;
|
45 |
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
47 |
display: grid;
|
48 |
// stylelint-disable-next-line unit-whitelist
|
49 |
grid-template-columns: repeat( auto-fit, minmax( 200px, 1fr ) );
|
50 |
grid-gap: 1.5em;
|
51 |
}
|
52 |
|
53 |
-
.components-base-control__label {
|
54 |
-
@include screen-reader-text();
|
55 |
-
}
|
56 |
-
|
57 |
.template-selector-control__label {
|
58 |
display: block;
|
59 |
width: 100%;
|
10 |
width: 1px;
|
11 |
word-wrap: normal !important;
|
12 |
}
|
13 |
+
|
14 |
+
// Full screen modal
|
15 |
.page-template-modal {
|
16 |
width: 100%;
|
17 |
height: 100vh;
|
18 |
+
}
|
19 |
|
20 |
+
// When not full screen account for sidebar
|
21 |
+
body:not( .is-fullscreen-mode ) .page-template-modal {
|
22 |
+
|
23 |
@media screen and ( min-width: 783px ) {
|
24 |
width: calc( 100% - 65px );
|
25 |
left: 50px;
|
49 |
.page-template-modal__list {
|
50 |
padding: 1.5em 0;
|
51 |
|
52 |
+
|
53 |
+
.components-base-control__label {
|
54 |
+
@include screen-reader-text();
|
55 |
+
}
|
56 |
+
|
57 |
+
.template-selector-control__options {
|
58 |
display: grid;
|
59 |
// stylelint-disable-next-line unit-whitelist
|
60 |
grid-template-columns: repeat( auto-fit, minmax( 200px, 1fr ) );
|
61 |
grid-gap: 1.5em;
|
62 |
}
|
63 |
|
|
|
|
|
|
|
|
|
64 |
.template-selector-control__label {
|
65 |
display: block;
|
66 |
width: 100%;
|
starter-page-templates/page-template-modal/utils/replace-placeholders.js
CHANGED
@@ -1,15 +1,20 @@
|
|
1 |
-
|
|
|
|
|
|
|
2 |
|
3 |
const PLACEHOLDER_DEFAULTS = {
|
4 |
-
Address: '123 Main St',
|
5 |
-
Phone: '555-555-5555',
|
6 |
-
CompanyName:
|
|
|
7 |
};
|
8 |
|
9 |
const KEY_MAP = {
|
10 |
CompanyName: 'title',
|
11 |
Address: 'address',
|
12 |
Phone: 'phone',
|
|
|
13 |
};
|
14 |
|
15 |
const replacePlaceholders = ( pageContent, siteInformation = {} ) => {
|
1 |
+
/**
|
2 |
+
* External dependencies
|
3 |
+
*/
|
4 |
+
import { _x } from '@wordpress/i18n';
|
5 |
|
6 |
const PLACEHOLDER_DEFAULTS = {
|
7 |
+
Address: _x( '123 Main St', 'default address', 'full-site-editing' ),
|
8 |
+
Phone: _x( '555-555-5555', 'default phone number', 'full-site-editing' ),
|
9 |
+
CompanyName: _x( 'Your Company Name', 'default company name', 'full-site-editing' ),
|
10 |
+
Vertical: _x( 'Business', 'default vertical name', 'full-site-editing' ),
|
11 |
};
|
12 |
|
13 |
const KEY_MAP = {
|
14 |
CompanyName: 'title',
|
15 |
Address: 'address',
|
16 |
Phone: 'phone',
|
17 |
+
Vertical: 'vertical',
|
18 |
};
|
19 |
|
20 |
const replacePlaceholders = ( pageContent, siteInformation = {} ) => {
|