Full Site Editing - Version 0.1.1

Version Description

  • Latest round of updates
Download this release

Release Info

Developer obenland
Plugin Icon wp plugin Full Site Editing
Version 0.1.1
Comparing to
See all releases

Code changes from version 0.1 to 0.1.1

Files changed (31) hide show
  1. full-site-editing-plugin.php +16 -2
  2. full-site-editing/blocks/post-content/edit.js +104 -0
  3. full-site-editing/blocks/post-content/index.js +30 -0
  4. full-site-editing/blocks/post-content/index.php +43 -0
  5. full-site-editing/blocks/post-content/style.scss +21 -0
  6. full-site-editing/blocks/template/edit.js +98 -0
  7. full-site-editing/blocks/template/index.js +30 -0
  8. full-site-editing/blocks/template/index.php +37 -0
  9. full-site-editing/blocks/template/style.scss +21 -0
  10. full-site-editing/class-a8c-rest-templates-controller.php +47 -0
  11. full-site-editing/class-full-site-editing.php +305 -0
  12. full-site-editing/components/post-autocomplete/index.js +113 -0
  13. full-site-editing/components/post-autocomplete/style.scss +24 -0
  14. full-site-editing/dist/full-site-editing.css +1 -0
  15. full-site-editing/dist/full-site-editing.deps.json +1 -0
  16. full-site-editing/dist/full-site-editing.js +12 -0
  17. full-site-editing/dist/full-site-editing.rtl.css +1 -0
  18. full-site-editing/index.js +6 -0
  19. full-site-editing/plugins/template-selector-sidebar/index.js +71 -0
  20. lib/feature-flags/feature-flags.php +116 -0
  21. lib/feature-flags/index.js +9 -0
  22. readme.txt +4 -1
  23. starter-page-templates/class-starter-page-templates.php +1 -0
  24. starter-page-templates/dist/starter-page-templates.css +1 -1
  25. starter-page-templates/dist/starter-page-templates.deps.json +1 -1
  26. starter-page-templates/dist/starter-page-templates.js +2 -2
  27. starter-page-templates/dist/starter-page-templates.rtl.css +1 -1
  28. starter-page-templates/page-template-modal/components/template-selector-control.js +25 -23
  29. starter-page-templates/page-template-modal/index.js +93 -68
  30. starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +12 -5
  31. 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-control__field{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));grid-gap:1.5em}.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__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}}
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=7)}([function(e,t){e.exports=wp.element},function(e,t){e.exports=lodash},function(e,t,n){var r;
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 o=typeof r;if("string"===o||"number"===o)e.push(r);else if(Array.isArray(r)&&r.length){var l=a.apply(null,r);l&&e.push(l)}else if("object"===o)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){e.exports=wp.compose},function(e,t){e.exports=wp.components},function(e,t,n){},,function(e,t,n){"use strict";n.r(t);var r,a=n(0),o={Address:"123 Main St",Phone:"555-555-5555",CompanyName:(r="Your Company Name",r)},l={CompanyName:"title",Address:"address",Phone:"phone"},c=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.replace(/{{(\w+)}}/g,function(e,n){var r=o[n];return t[l[n]]||r||n})},s=(n(5),n(1)),i=n(2),p=n.n(i),u=n(3),m=n(4);var f=Object(u.withInstanceId)(function(e){var t=e.label,n=e.className,r=e.help,o=e.instanceId,l=e.onClick,c=e.templates,i=void 0===c?[]:c,u="inspector-radio-control-".concat(o),f=function(e){return l(e.target.value)};return Object(s.isEmpty)(i)?null:Object(a.createElement)(m.BaseControl,{label:t,id:u,help:r,className:p()(n,"template-selector-control")},i.map(function(e,t){return Object(a.createElement)("div",{key:"".concat(u,"-").concat(t),className:"template-selector-control__option"},Object(a.createElement)("button",{type:"button",id:"".concat(u,"-").concat(t),className:"template-selector-control__label",value:e.value,onClick:f,"aria-describedby":r?"".concat(u,"__help"):void 0},Object(a.createElement)("div",{className:"template-selector-control__media-wrap"},e.preview&&Object(a.createElement)("img",{className:"template-selector-control__media",src:e.preview,alt:"Preview of "+e.label})),e.label))}))});if(window.starterPageTemplatesConfig){var d={home:"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-home-2.png",menu:"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-menu-2.png","contact-us":"https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-contactus-2.png"};window.starterPageTemplatesConfig.templates=Object(s.map)(window.starterPageTemplatesConfig.templates,function(e){return e.preview=d[e.slug],e})}!function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=e.plugins.registerPlugin,r=e.components.Modal,o=e.compose.withState,l=t.siteInformation,i=void 0===l?{}:l,p=t.templates,u=void 0===p?[]:p,m=o({isOpen:!0,isLoading:!1,verticalTemplates:Object(s.keyBy)(u,"slug")})(function(t){var n=t.isOpen,o=t.verticalTemplates,l=t.setState;return Object(a.createElement)("div",null,n&&Object(a.createElement)(r,{title:"Select Page Template",onRequestClose:function(){return l({isOpen:!1})},className:"page-template-modal"},Object(a.createElement)("div",{className:"page-template-modal__inner"},Object(a.createElement)("div",{className:"page-template-modal__intro"},Object(a.createElement)("p",null,"Pick a Template that matches the purpose of your page."),Object(a.createElement)("p",null,"You can customise each Template to meet your needs.")),Object(a.createElement)("form",{className:"page-template-modal__form"},Object(a.createElement)("fieldset",{className:"page-template-modal__list"},Object(a.createElement)(f,{label:"Template",templates:Object.values(o).map(function(e){return{label:e.title,value:e.slug,preview:e.preview}}),onClick:function(t){l({isOpen:!1}),function(t){if(Object(s.has)(t,"content")){e.data.dispatch("core/editor").editPost({title:c(t.title,i)});var n=c(t.content,i),r=e.blocks.parse(n);e.data.dispatch("core/editor").insertBlocks(r)}}(o[t])}}))))))});n("page-templates",{render:function(){return Object(a.createElement)(m,null)}})}(window.wp,window.starterPageTemplatesConfig)}]));
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-control__field{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));grid-gap:1.5em}.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__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}}
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
- { templates.map( ( option, index ) => (
36
- <div key={ `${ id }-${ index }` } className="template-selector-control__option">
37
- <button
38
- type="button"
39
- id={ `${ id }-${ index }` }
40
- className="template-selector-control__label"
41
- value={ option.value }
42
- onClick={ handleButtonClick }
43
- aria-describedby={ help ? `${ id }__help` : undefined }
44
- >
45
- <div className="template-selector-control__media-wrap">
46
- { option.preview && (
47
- <img
48
- className="template-selector-control__media"
49
- src={ option.preview }
50
- alt={ 'Preview of ' + option.label }
51
- />
52
- ) }
53
- </div>
54
- { option.label }
55
- </button>
56
- </div>
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: 'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-home-2.png',
13
- menu: 'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-menu-2.png',
14
- 'contact-us':
15
- 'https://starterpagetemplatesprototype.files.wordpress.com/2019/05/starter-contactus-2.png',
16
};
17
window.starterPageTemplatesConfig.templates = map(
18
window.starterPageTemplatesConfig.templates,
@@ -23,71 +43,76 @@ if ( window.starterPageTemplatesConfig ) {
23
);
24
}
25
26
- ( function( wp, config = {} ) {
27
- const registerPlugin = wp.plugins.registerPlugin;
28
- const { Modal } = wp.components;
29
- const { withState } = wp.compose;
30
31
- const { siteInformation = {}, templates = [] } = config;
32
33
- const insertTemplate = template => {
34
- // Skip inserting if there's nothing to insert.
35
- if ( ! has( template, 'content' ) ) {
36
- return;
37
- }
38
39
- // set title
40
- wp.data
41
- .dispatch( 'core/editor' )
42
- .editPost( { title: replacePlaceholders( template.title, siteInformation ) } );
43
44
- // load content
45
- const templateString = replacePlaceholders( template.content, siteInformation );
46
- const blocks = wp.blocks.parse( templateString );
47
- wp.data.dispatch( 'core/editor' ).insertBlocks( blocks );
48
- };
49
50
- const PageTemplateModal = withState( {
51
- isOpen: true,
52
- isLoading: false,
53
- verticalTemplates: keyBy( templates, 'slug' ),
54
- } )( ( { isOpen, verticalTemplates, setState } ) => (
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
- .components-base-control__field {
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
- const __ = a => a;
2
3
const PLACEHOLDER_DEFAULTS = {
4
- Address: '123 Main St',
5
- Phone: '555-555-5555',
6
- CompanyName: __( 'Your Company Name' ),
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 = {} ) => {