Full Site Editing - Version 0.2

Version Description

  • Bug fixes and performance improvements.
Download this release

Release Info

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

Code changes from version 0.1.1 to 0.2

Files changed (43) hide show
  1. full-site-editing-plugin.php +65 -7
  2. full-site-editing/blocks/navigation-menu/edit.js +46 -0
  3. full-site-editing/blocks/navigation-menu/index.js +38 -0
  4. full-site-editing/blocks/navigation-menu/index.php +95 -0
  5. full-site-editing/blocks/navigation-menu/style.scss +140 -0
  6. full-site-editing/blocks/post-content/index.js +18 -17
  7. full-site-editing/blocks/post-content/index.php +8 -5
  8. full-site-editing/blocks/site-description/edit.js +92 -0
  9. full-site-editing/blocks/site-description/index.js +25 -0
  10. full-site-editing/blocks/site-description/index.php +27 -0
  11. full-site-editing/blocks/site-description/style.scss +10 -0
  12. full-site-editing/blocks/site-logo/edit.js +41 -0
  13. full-site-editing/blocks/site-logo/index.js +21 -0
  14. full-site-editing/blocks/site-logo/index.php +44 -0
  15. full-site-editing/blocks/site-logo/style.scss +3 -0
  16. full-site-editing/blocks/template/edit.js +29 -7
  17. full-site-editing/blocks/template/index.js +1 -1
  18. full-site-editing/blocks/template/index.php +5 -3
  19. full-site-editing/blocks/template/style.scss +17 -0
  20. full-site-editing/class-full-site-editing.php +254 -2
  21. full-site-editing/dist/full-site-editing.css +1 -1
  22. full-site-editing/dist/full-site-editing.deps.json +1 -1
  23. full-site-editing/dist/full-site-editing.js +2 -2
  24. full-site-editing/dist/full-site-editing.rtl.css +1 -1
  25. full-site-editing/index.js +5 -0
  26. full-site-editing/plugins/close-button-override/index.js +24 -0
  27. full-site-editing/plugins/template-update-confirmation/button.js +143 -0
  28. full-site-editing/plugins/template-update-confirmation/index.js +21 -0
  29. full-site-editing/plugins/template-update-confirmation/panel.js +40 -0
  30. full-site-editing/utils/class-a8c-wp-template-data-inserter.php +105 -0
  31. full-site-editing/utils/class-a8c-wp-template.php +200 -0
  32. full-site-editing/utils/replace-template-parts.php +68 -0
  33. lib/feature-flags/class-a8c-full-site-editing-feature-flags.php +118 -0
  34. readme.txt +4 -1
  35. starter-page-templates/class-starter-page-templates.php +97 -22
  36. starter-page-templates/dist/starter-page-templates.css +1 -1
  37. starter-page-templates/dist/starter-page-templates.deps.json +1 -1
  38. starter-page-templates/dist/starter-page-templates.js +2 -2
  39. starter-page-templates/dist/starter-page-templates.rtl.css +1 -1
  40. starter-page-templates/page-template-modal/components/template-selector-control.js +1 -1
  41. starter-page-templates/page-template-modal/index.js +113 -62
  42. starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss +33 -13
  43. starter-page-templates/page-template-modal/utils/tracking.js +59 -0
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.1
6
  * Author: Automattic
7
  * Author URI: https://automattic.com/wordpress-plugins/
8
  * License: GPLv2 or later
@@ -15,25 +15,48 @@
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
  */
31
  function a8c_load_posts_list_block() {
32
- if ( function_exists( 'is_automattician' ) && ! is_automattician() ) {
33
  return;
34
  }
35
 
36
- if ( class_exists( 'Posts_List_Block' ) ) {
 
 
 
 
 
 
 
37
  return;
38
  }
39
 
@@ -48,7 +71,14 @@ add_action( 'plugins_loaded', 'a8c_load_posts_list_block' );
48
  * Load Starter_Page_Templates.
49
  */
50
  function a8c_load_starter_page_templates() {
51
- if ( function_exists( 'is_automattician' ) && ! is_automattician() ) {
 
 
 
 
 
 
 
52
  return;
53
  }
54
 
@@ -56,4 +86,32 @@ function a8c_load_starter_page_templates() {
56
 
57
  Starter_Page_Templates::get_instance();
58
  }
59
- //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.2
6
  * Author: Automattic
7
  * Author URI: https://automattic.com/wordpress-plugins/
8
  * License: GPLv2 or later
15
  * Load Full Site Editing.
16
  */
17
  function a8c_load_full_site_editing() {
18
+ /**
19
+ * Can be used to disable Full Site Editing functionality.
20
+ *
21
+ * @since 0.2
22
+ *
23
+ * @param bool true if Full Site Editing should be disabled, false otherwise.
24
+ */
25
+ if ( apply_filters( 'a8c_disable_full_site_editing', false ) ) {
26
+ return;
27
+ }
28
+
29
+ require_once __DIR__ . '/lib/feature-flags/class-a8c-full-site-editing-feature-flags.php';
30
+ require_once __DIR__ . '/full-site-editing/blocks/navigation-menu/index.php';
31
  require_once __DIR__ . '/full-site-editing/blocks/post-content/index.php';
32
+ require_once __DIR__ . '/full-site-editing/blocks/site-description/index.php';
33
  require_once __DIR__ . '/full-site-editing/blocks/template/index.php';
34
+ require_once __DIR__ . '/full-site-editing/blocks/site-logo/index.php';
35
  require_once __DIR__ . '/full-site-editing/class-a8c-rest-templates-controller.php';
36
  require_once __DIR__ . '/full-site-editing/class-full-site-editing.php';
37
+ require_once __DIR__ . '/full-site-editing/utils/class-a8c-wp-template.php';
38
+ require_once __DIR__ . '/full-site-editing/utils/replace-template-parts.php';
39
 
40
  Full_Site_Editing::get_instance();
41
  }
42
+ add_action( 'plugins_loaded', 'a8c_load_full_site_editing' );
43
 
44
  /**
45
  * Load Posts List Block.
46
  */
47
  function a8c_load_posts_list_block() {
48
+ if ( class_exists( 'Posts_List_Block' ) ) {
49
  return;
50
  }
51
 
52
+ /**
53
+ * Can be used to disable the Post List Block.
54
+ *
55
+ * @since 0.2
56
+ *
57
+ * @param bool true if Post List Block should be disabled, false otherwise.
58
+ */
59
+ if ( apply_filters( 'a8c_disable_post_list_block', false ) ) {
60
  return;
61
  }
62
 
71
  * Load Starter_Page_Templates.
72
  */
73
  function a8c_load_starter_page_templates() {
74
+ /**
75
+ * Can be used to disable the Starter Page Templates.
76
+ *
77
+ * @since 0.2
78
+ *
79
+ * @param bool true if Starter Page Templates should be disabled, false otherwise.
80
+ */
81
+ if ( apply_filters( 'a8c_disable_starter_page_templates', false ) ) {
82
  return;
83
  }
84
 
86
 
87
  Starter_Page_Templates::get_instance();
88
  }
89
+ add_action( 'plugins_loaded', 'a8c_load_starter_page_templates' );
90
+
91
+ /**
92
+ * Set up the required plugin data on activation.
93
+ *
94
+ * Creates the default template that all pages use along with
95
+ * the required template parts like header and footer.
96
+ */
97
+ function a8c_fse_on_plugin_activation() {
98
+ /**
99
+ * Can be used to disable Full Site Editing functionality.
100
+ *
101
+ * @since 0.1
102
+ *
103
+ * @param bool true if Full Site Editing should be disabled, false otherwise.
104
+ */
105
+ if ( apply_filters( 'a8c_disable_full_site_editing', false ) ) {
106
+ return;
107
+ }
108
+
109
+ require_once __DIR__ . '/full-site-editing/class-full-site-editing.php';
110
+ $fse = Full_Site_Editing::get_instance();
111
+ $fse->register_template_post_types();
112
+
113
+ require_once __DIR__ . '/full-site-editing/utils/class-a8c-wp-template-data-inserter.php';
114
+ $data_inserter = new A8C_WP_Template_Data_Inserter();
115
+ $data_inserter->insert_default_template_data();
116
+ }
117
+ register_activation_hook( __FILE__, 'a8c_fse_on_plugin_activation' );
full-site-editing/blocks/navigation-menu/edit.js ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint-disable wpcalypso/jsx-classname-namespace */
2
+ /**
3
+ * External dependencies
4
+ */
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { IconButton, ServerSideRender, Toolbar } from '@wordpress/components';
10
+ import { BlockControls } from '@wordpress/editor';
11
+ import { addQueryArgs } from '@wordpress/url';
12
+ import { Fragment } from '@wordpress/element';
13
+ import { __ } from '@wordpress/i18n';
14
+
15
+ /**
16
+ * Internal dependencies
17
+ */
18
+
19
+ const NavigationMenuEdit = ( { attributes } ) => {
20
+ const url = addQueryArgs( 'customize.php', {
21
+ 'autofocus[panel]': 'nav_menus',
22
+ return: window.location.href,
23
+ } );
24
+
25
+ return (
26
+ <Fragment>
27
+ <BlockControls>
28
+ <Toolbar className="wp-block-a8c-navigation-menu-toolbar">
29
+ <IconButton
30
+ icon="edit"
31
+ label={ __( 'Edit Menu' ) }
32
+ href={ url }
33
+ className="components-toolbar__control"
34
+ />
35
+ </Toolbar>
36
+ </BlockControls>
37
+ <ServerSideRender
38
+ attributes={ attributes }
39
+ block="a8c/navigation-menu"
40
+ className="wp-block-a8c-navigation-menu"
41
+ />
42
+ </Fragment>
43
+ );
44
+ };
45
+
46
+ export default NavigationMenuEdit;
full-site-editing/blocks/navigation-menu/index.js ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { registerBlockType } from '@wordpress/blocks';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import edit from './edit';
11
+ import './style.scss';
12
+
13
+ const icon = (
14
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
15
+ <path fill="none" d="M0 0h24v24H0V0z" />
16
+ <path d="M12 7.27l4.28 10.43-3.47-1.53-.81-.36-.81.36-3.47 1.53L12 7.27M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71L12 2z" />
17
+ </svg>
18
+ );
19
+
20
+ registerBlockType( 'a8c/navigation-menu', {
21
+ title: __( 'Navigation Menu' ),
22
+ description: __( 'Visual placeholder for site-wide navigation and menus.' ),
23
+ icon,
24
+ category: 'layout',
25
+ supports: {
26
+ html: false,
27
+ multiple: false,
28
+ reusable: false,
29
+ },
30
+ attributes: {
31
+ themeLocation: {
32
+ type: 'string',
33
+ default: 'main-1',
34
+ },
35
+ },
36
+ edit,
37
+ save: () => null,
38
+ } );
full-site-editing/blocks/navigation-menu/index.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Render navigation menus.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Determines necessary wp_nav_menu() parameters by given theme location.
10
+ *
11
+ * @param string $location Theme location.
12
+ * @return array
13
+ */
14
+ function get_menu_params_by_theme_location( $location ) {
15
+ switch ( $location ) {
16
+ case 'footer':
17
+ $params = [
18
+ 'theme_location' => 'footer',
19
+ 'menu_class' => 'footer-menu',
20
+ 'depth' => 1,
21
+ ];
22
+ break;
23
+ case 'social':
24
+ $params = [
25
+ 'theme_location' => 'social',
26
+ 'menu_class' => 'social-links-menu',
27
+ 'link_before' => '<span class="screen-reader-text">',
28
+ 'link_after' => '</span>' . twentynineteen_get_icon_svg( 'link' ),
29
+ 'depth' => 1,
30
+ ];
31
+ break;
32
+ case 'main-1':
33
+ default:
34
+ $params = [
35
+ 'theme_location' => 'menu-1',
36
+ 'menu_class' => 'main-menu',
37
+ 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
38
+ 'depth' => 1,
39
+ ];
40
+ break;
41
+ }
42
+ return $params;
43
+ }
44
+
45
+ /**
46
+ * Determines necessary attributes for the wrapping `nav` element.
47
+ *
48
+ * @param string $location Theme location.
49
+ * @return array
50
+ */
51
+ function get_wrapper_attributes_by_theme_location( $location ) {
52
+ switch ( $location ) {
53
+ case 'footer':
54
+ $attributes = [
55
+ 'class' => 'footer-navigation',
56
+ 'label' => 'Footer Menu',
57
+ ];
58
+ break;
59
+ case 'social':
60
+ $attributes = [
61
+ 'class' => 'social-navigation',
62
+ 'label' => 'Social Links Menu',
63
+ ];
64
+ break;
65
+ case 'main-1':
66
+ default:
67
+ $attributes = [
68
+ 'class' => 'main-navigation',
69
+ 'label' => 'Top Menu',
70
+ ];
71
+ break;
72
+ }
73
+ return $attributes;
74
+ }
75
+
76
+ /**
77
+ * Renders post content.
78
+ *
79
+ * @param array $attributes Block attributes.
80
+ * @return string
81
+ */
82
+ function render_navigation_menu_block( $attributes ) {
83
+ $location = ! empty( $attributes['themeLocation'] ) ? $attributes['themeLocation'] : null;
84
+ $wrapper_attr = get_wrapper_attributes_by_theme_location( $location );
85
+ ob_start();
86
+ // phpcs:disable WordPress.WP.I18n.NonSingularStringLiteralText
87
+ ?>
88
+ <nav class="<?php echo esc_attr( $wrapper_attr['class'] ); ?>" aria-label="<?php esc_attr_e( $wrapper_attr['label'], 'twentynineteen' ); ?>">
89
+ <?php
90
+ wp_nav_menu( get_menu_params_by_theme_location( $location ) );
91
+ ?>
92
+ </nav><!-- #site-navigation -->
93
+ <?php
94
+ return ob_get_clean();
95
+ }
full-site-editing/blocks/navigation-menu/style.scss ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .wp-block-a8c-navigation-menu .main-navigation {
2
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
3
+ font-size: 1.125em;
4
+ font-weight: 700;
5
+ letter-spacing: -0.02em;
6
+ line-height: 1.2;
7
+ pointer-events: none;
8
+ -webkit-font-smoothing: antialiased;
9
+ }
10
+
11
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu {
12
+ display: inline-block;
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li {
18
+ color: #0073aa;
19
+ display: inline;
20
+ position: relative;
21
+ }
22
+
23
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li > a {
24
+ font-weight: 700;
25
+ color: #0073aa;
26
+ margin-right: 0.5rem;
27
+ }
28
+
29
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li:last-child > a, .main-navigation .main-menu > li:last-child.menu-item-has-children .submenu-expand {
30
+ margin-right: 0;
31
+ }
32
+
33
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li.menu-item-has-children > a {
34
+ margin-right: 0.125rem;
35
+ }
36
+
37
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li.menu-item-has-children {
38
+ display: inline-block;
39
+ position: inherit;
40
+ }
41
+
42
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li.menu-item-has-children .submenu-expand {
43
+ display: inline-block;
44
+ margin-right: 0.25rem;
45
+ }
46
+
47
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li.menu-item-has-children .submenu-expand svg {
48
+ position: relative;
49
+ top: 0.3rem;
50
+ }
51
+
52
+ .wp-block-a8c-navigation-menu .main-navigation .main-menu > li > a:hover, .main-navigation .main-menu > li > a:hover + svg {
53
+ color: #005177;
54
+ }
55
+
56
+ .wp-block-a8c-navigation-menu .main-navigation svg {
57
+ transition: fill 120ms ease-in-out;
58
+ fill: currentColor;
59
+ }
60
+
61
+ .wp-block-a8c-navigation-menu .main-navigation a {
62
+ text-decoration: none;
63
+ }
64
+
65
+ .wp-block-a8c-navigation-menu .main-navigation button {
66
+ display: inline-block;
67
+ border: none;
68
+ padding: 0;
69
+ margin: 0;
70
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
71
+ font-size: 0.88889em;
72
+ font-weight: 700;
73
+ line-height: 1.2;
74
+ text-decoration: none;
75
+ vertical-align: bottom;
76
+ background: transparent;
77
+ color: inherit;
78
+ cursor: pointer;
79
+ transition: background 250ms ease-in-out, transform 150ms ease;
80
+ -webkit-appearance: none;
81
+ -moz-appearance: none;
82
+ }
83
+
84
+ .wp-block-a8c-navigation-menu .main-menu-more {
85
+ display: none;
86
+ }
87
+
88
+ .wp-block-a8c-navigation-menu .social-navigation {
89
+ line-height: 1.25;
90
+ margin-top: calc( 1rem / 2 );
91
+ text-align: left;
92
+ }
93
+
94
+ .wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu {
95
+ content: '';
96
+ display: inline-block;
97
+ margin: 0;
98
+ padding: 0;
99
+ }
100
+
101
+ .wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li {
102
+ display: inline-block;
103
+ vertical-align: bottom;
104
+ vertical-align: -webkit-baseline-middle;
105
+ list-style: none;
106
+ }
107
+
108
+ .wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li a svg {
109
+ display: block;
110
+ width: 32px;
111
+ height: 32px;
112
+ transform: translateZ( 0 );
113
+ }
114
+
115
+ .wp-block-a8c-navigation-menu .footer-navigation .footer-menu {
116
+ display: inline;
117
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
118
+ font-size: 0.71111em;
119
+ padding-left: 0;
120
+ }
121
+
122
+ .wp-block-a8c-navigation-menu .footer-navigation .footer-menu li {
123
+ display: inline;
124
+ margin-right: 1rem;
125
+ }
126
+
127
+ .wp-block-a8c-navigation-menu .footer-navigation .footer-menu a {
128
+ text-decoration: none;
129
+ color: #767676;
130
+ }
131
+
132
+ .wp-block-a8c-navigation-menu .footer-navigation .footer-menu a:hover {
133
+ text-decoration: none;
134
+ color: #0073aa;
135
+ }
136
+
137
+ .editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a,
138
+ .editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a:hover {
139
+ color: #555d66;
140
+ }
full-site-editing/blocks/post-content/index.js CHANGED
@@ -3,6 +3,7 @@
3
  * WordPress dependencies
4
  */
5
  import { registerBlockType } from '@wordpress/blocks';
 
6
  import { __ } from '@wordpress/i18n';
7
 
8
  /**
@@ -11,20 +12,20 @@ import { __ } from '@wordpress/i18n';
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
- }
3
  * WordPress dependencies
4
  */
5
  import { registerBlockType } from '@wordpress/blocks';
6
+ import { InnerBlocks } from '@wordpress/block-editor';
7
  import { __ } from '@wordpress/i18n';
8
 
9
  /**
12
  import edit from './edit';
13
  import './style.scss';
14
 
15
+ const isTemplatePostType = 'wp_template' === fullSiteEditing.editorPostType;
16
+
17
+ registerBlockType( 'a8c/post-content', {
18
+ title: __( 'Content Slot' ),
19
+ description: __( 'Placeholder for a post or a page.' ),
20
+ icon: 'layout',
21
+ category: 'layout',
22
+ supports: {
23
+ align: [ 'wide', 'full' ],
24
+ anchor: true,
25
+ html: false,
26
+ multiple: false,
27
+ reusable: false,
28
+ },
29
+ edit: isTemplatePostType ? edit : () => <InnerBlocks />,
30
+ save: isTemplatePostType ? () => null : () => <InnerBlocks.Content />,
31
+ } );
full-site-editing/blocks/post-content/index.php CHANGED
@@ -13,13 +13,13 @@
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.
@@ -32,8 +32,11 @@ function render_post_content_block( $attributes, $content ) {
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
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.
32
  ob_start();
33
  ?>
34
 
35
+ <div class="post-content<?php echo esc_attr( $align ); ?>">
36
+ <?php
37
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
38
+ echo apply_filters( 'the_content', get_the_content() );
39
+ ?>
40
  </div><!-- .post-content -->
41
 
42
  <?php
full-site-editing/blocks/site-description/edit.js ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import apiFetch from '@wordpress/api-fetch';
5
+ import { PlainText } from '@wordpress/block-editor';
6
+ import { withNotices } from '@wordpress/components';
7
+ import { compose } from '@wordpress/compose';
8
+ import { withSelect } from '@wordpress/data';
9
+ import { Component, Fragment } from '@wordpress/element';
10
+ import { __ } from '@wordpress/i18n';
11
+
12
+ class SiteDescriptionEdit extends Component {
13
+ state = {
14
+ description: __( 'Site description loading…' ),
15
+ initialDescription: '',
16
+ };
17
+
18
+ componentDidMount() {
19
+ const { noticeOperations } = this.props;
20
+
21
+ return apiFetch( { path: '/wp/v2/settings' } )
22
+ .then( ( { description } ) =>
23
+ this.setState( { initialDescription: description, description } )
24
+ )
25
+ .catch( ( { message } ) => {
26
+ noticeOperations.createErrorNotice( message );
27
+ } );
28
+ }
29
+
30
+ componentDidUpdate( prevProps ) {
31
+ const { description, initialDescription } = this.state;
32
+ const { shouldUpdateSiteOption, noticeOperations, isSelected } = this.props;
33
+
34
+ const descriptionUnchanged = description && description.trim() === initialDescription.trim();
35
+ const descriptionIsEmpty = ! description || description.trim().length === 0;
36
+
37
+ // Reset to initial value if user de-selects the block with an empty value.
38
+ if ( ! isSelected && prevProps.isSelected && descriptionIsEmpty ) {
39
+ this.revertDescription();
40
+ }
41
+
42
+ // Don't do anything further if we shouldn't update the site option or the value is unchanged.
43
+ if ( ! shouldUpdateSiteOption || descriptionUnchanged ) {
44
+ return;
45
+ }
46
+
47
+ if ( ! prevProps.shouldUpdateSiteOption && shouldUpdateSiteOption ) {
48
+ apiFetch( { path: '/wp/v2/settings', method: 'POST', data: { description } } )
49
+ .then( () => this.updateInitialDescription() )
50
+ .catch( ( { message } ) => {
51
+ noticeOperations.createErrorNotice( message );
52
+ this.revertDescription();
53
+ } );
54
+ }
55
+ }
56
+
57
+ revertDescription = () => this.setState( { description: this.state.initialDescription } );
58
+
59
+ updateInitialDescription = () => this.setState( { initialDescription: this.state.description } );
60
+
61
+ render() {
62
+ const { className, noticeUI } = this.props;
63
+ const { description } = this.state;
64
+
65
+ return (
66
+ <Fragment>
67
+ { noticeUI }
68
+ <PlainText
69
+ className={ className }
70
+ value={ description }
71
+ onChange={ value => this.setState( { description: value } ) }
72
+ placeholder={ __( 'Site Description' ) }
73
+ aria-label={ __( 'Site Description' ) }
74
+ />
75
+ </Fragment>
76
+ );
77
+ }
78
+ }
79
+
80
+ export default compose( [
81
+ withSelect( select => {
82
+ const { isSavingPost, isPublishingPost, isAutosavingPost, isCurrentPostPublished } = select(
83
+ 'core/editor'
84
+ );
85
+ return {
86
+ shouldUpdateSiteOption:
87
+ ( ( isSavingPost() && isCurrentPostPublished() ) || isPublishingPost() ) &&
88
+ ! isAutosavingPost(),
89
+ };
90
+ } ),
91
+ withNotices,
92
+ ] )( SiteDescriptionEdit );
full-site-editing/blocks/site-description/index.js ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { registerBlockType } from '@wordpress/blocks';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import edit from './edit';
11
+ import './style.scss';
12
+
13
+ registerBlockType( 'a8c/site-description', {
14
+ title: __( 'Site Description2' ),
15
+ description: __( 'Site description, also known as the tagline.' ),
16
+ icon: 'layout',
17
+ category: 'layout',
18
+ supports: {
19
+ html: false,
20
+ multiple: false,
21
+ reusable: false,
22
+ },
23
+ edit,
24
+ save: () => null,
25
+ } );
full-site-editing/blocks/site-description/index.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Render site description file.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Renders the site description (tagline) block.
10
+ *
11
+ * @return string
12
+ */
13
+ function render_site_description_block( $attributes ) {
14
+ ob_start();
15
+
16
+ $class = 'site-description wp-block-a8c-site-description';
17
+ if ( isset( $attributes['className'] ) ) {
18
+ $class .= ' ' . $attributes['className'];
19
+ }
20
+
21
+ ?>
22
+ <p class="<?php echo esc_attr( $class ); ?>">
23
+ <?php bloginfo( 'description' ); ?>
24
+ </p>
25
+ <?php
26
+ return ob_get_clean();
27
+ }
full-site-editing/blocks/site-description/style.scss ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ .block-editor .wp-block-a8c-site-description {
2
+ &, &:focus {
3
+ display: inline;
4
+ color: #767676;
5
+ font-size: 1.125em;
6
+ font-weight: normal;
7
+ letter-spacing: -0.01em;
8
+ margin: 0;
9
+ }
10
+ }
full-site-editing/blocks/site-logo/edit.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint-disable wpcalypso/jsx-classname-namespace */
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { IconButton, ServerSideRender, Toolbar } from '@wordpress/components';
6
+ import { Fragment } from '@wordpress/element';
7
+ import { BlockControls } from '@wordpress/editor';
8
+ import { __ } from '@wordpress/i18n';
9
+ import { addQueryArgs } from '@wordpress/url';
10
+
11
+ function SiteLogoEdit( { className } ) {
12
+ const navigateToCustomerSiteIdentity = () => {
13
+ const siteIdentityLink = addQueryArgs( 'customize.php', {
14
+ 'autofocus[section]': 'title_tagline',
15
+ return: window.location.href,
16
+ } );
17
+ window.location.href = siteIdentityLink;
18
+ };
19
+
20
+ return (
21
+ <Fragment>
22
+ <BlockControls>
23
+ <Toolbar>
24
+ <IconButton
25
+ className={ 'components-toolbar__control' }
26
+ icon="edit"
27
+ label={ __( 'Edit Site Logo' ) }
28
+ onClick={ navigateToCustomerSiteIdentity }
29
+ />
30
+ </Toolbar>
31
+ </BlockControls>
32
+ <ServerSideRender
33
+ className={ className }
34
+ block="a8c/site-logo"
35
+ attributes={ { editorPreview: true } }
36
+ />
37
+ </Fragment>
38
+ );
39
+ }
40
+
41
+ export default SiteLogoEdit;
full-site-editing/blocks/site-logo/index.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { registerBlockType } from '@wordpress/blocks';
5
+ import { __ } from '@wordpress/i18n';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import edit from './edit';
11
+ import './style.scss';
12
+
13
+ registerBlockType( 'a8c/site-logo', {
14
+ title: __( 'Site Logo' ),
15
+ description: __( 'Site Logo' ),
16
+ icon: 'format-image',
17
+ category: 'layout',
18
+ keywords: [ __( 'logo' ), __( 'icon' ), __( 'site' ) ],
19
+ edit,
20
+ save: () => null,
21
+ } );
full-site-editing/blocks/site-logo/index.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Render site-logo block file.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Renders a site-logo.
10
+ *
11
+ * @param array $attributes Block attributes.
12
+ * @param string $content Block content.
13
+ * @return string
14
+ */
15
+ function render_site_logo( $attributes, $content ) {
16
+ if ( $attributes[ 'editorPreview' ] === true ) {
17
+ return render_site_logo_editor_preview( $attributes, $content );
18
+ }
19
+ return render_site_logo_publish( $attributes, $content );
20
+ }
21
+
22
+ function render_site_logo_publish( $attributes, $content ) {
23
+ if ( ! function_exists( 'get_custom_logo' ) || ! function_exists( 'has_custom_logo' ) ) {
24
+ return '';
25
+ }
26
+
27
+ if ( ! has_custom_logo() ) {
28
+ return '';
29
+ }
30
+
31
+ return get_custom_logo();
32
+ }
33
+
34
+ function render_site_logo_editor_preview( $attributes, $content ) {
35
+ if ( ! function_exists( 'get_custom_logo' ) || ! function_exists( 'has_custom_logo' ) ) {
36
+ return sprintf( '<div class="components-placeholder"><div class="components-placeholder__label">%1$s</div></components-placeholder__label><div class="components-placeholder__instructions">%2$s</div></div>', __( 'Site Logo', 'full-site-editing' ), __( 'No Logo Support!', 'full-site-editing' ) );
37
+ }
38
+
39
+ if ( ! has_custom_logo() ) {
40
+ return sprintf( '<div class="components-placeholder has-no-logo"><div class="components-placeholder__label">%1$s</div></components-placeholder__label><div class="components-placeholder__instructions">%2$s</div></div>', __( 'Site Logo', 'full-site-editing' ), __( 'Click on the Edit button to select a Site Logo.', 'full-site-editing' ) );
41
+ }
42
+
43
+ return get_custom_logo();
44
+ }
full-site-editing/blocks/site-logo/style.scss ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ .wp-block-a8c-site-logo {
2
+ pointer-events: none;
3
+ }
full-site-editing/blocks/template/edit.js CHANGED
@@ -1,4 +1,5 @@
1
  /* eslint-disable wpcalypso/jsx-classname-namespace */
 
2
  /**
3
  * External dependencies
4
  */
@@ -8,7 +9,7 @@ import { get } from 'lodash';
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';
@@ -24,13 +25,16 @@ import './style.scss';
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 } );
@@ -43,10 +47,11 @@ const TemplateEdit = compose(
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
@@ -78,7 +83,7 @@ const TemplateEdit = compose(
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
  ) }
@@ -86,9 +91,26 @@ const TemplateEdit = compose(
86
  </Placeholder>
87
  ) }
88
  { showContent && (
89
- <RawHTML className="template-block__content">
90
- { get( template, [ 'content', 'rendered' ] ) }
91
- </RawHTML>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  ) }
93
  </div>
94
  </Fragment>
1
  /* eslint-disable wpcalypso/jsx-classname-namespace */
2
+ /* global fullSiteEditing */
3
  /**
4
  * External dependencies
5
  */
9
  /**
10
  * WordPress dependencies
11
  */
12
+ import { Button, IconButton, Placeholder, Toolbar } from '@wordpress/components';
13
  import { compose, withState } from '@wordpress/compose';
14
  import { withSelect } from '@wordpress/data';
15
  import { BlockControls } from '@wordpress/editor';
25
  const TemplateEdit = compose(
26
  withSelect( ( select, { attributes } ) => {
27
  const { getEntityRecord } = select( 'core' );
28
+ const { getCurrentPostId } = select( 'core/editor' );
29
+
30
  const { templateId } = attributes;
31
  return {
32
+ currentPostId: getCurrentPostId(),
33
  template: templateId && getEntityRecord( 'postType', 'wp_template_part', templateId ),
34
  };
35
  } ),
36
  withState( { isEditing: false } )
37
+ )( ( { attributes, currentPostId, isEditing, template, setAttributes, setState } ) => {
38
  const { align, templateId } = attributes;
39
 
40
  const toggleEditing = () => setState( { isEditing: ! isEditing } );
47
  const showToggleButton = ! isEditing || !! templateId;
48
  const showPlaceholder = isEditing || ! templateId;
49
  const showContent = ! isEditing && !! templateId;
50
+ const isTemplate = 'wp_template' === fullSiteEditing.editorPostType;
51
 
52
  return (
53
  <Fragment>
54
+ { showToggleButton && isTemplate && (
55
  <BlockControls>
56
  <Toolbar>
57
  <IconButton
83
  postType="wp_template_part"
84
  />
85
  { !! template && (
86
+ <a href={ `?post=${ templateId }&action=edit&fse_parent_post=${ currentPostId }` }>
87
  { sprintf( __( 'Edit "%s"' ), get( template, [ 'title', 'rendered' ], '' ) ) }
88
  </a>
89
  ) }
91
  </Placeholder>
92
  ) }
93
  { showContent && (
94
+ <Fragment>
95
+ <RawHTML className="template-block__content">
96
+ { get( template, [ 'content', 'rendered' ] ) }
97
+ </RawHTML>
98
+ { ! isTemplate && (
99
+ <Placeholder
100
+ className="template-block__overlay"
101
+ instructions={ __(
102
+ 'This block is part of your site template and may appear on multiple pages.'
103
+ ) }
104
+ >
105
+ <Button
106
+ href={ `?post=${ templateId }&action=edit&fse_parent_post=${ currentPostId }` }
107
+ isDefault
108
+ >
109
+ { sprintf( __( 'Edit %s' ), get( template, [ 'title', 'rendered' ], '' ) ) }
110
+ </Button>
111
+ </Placeholder>
112
+ ) }
113
+ </Fragment>
114
  ) }
115
  </div>
116
  </Fragment>
full-site-editing/blocks/template/index.js CHANGED
@@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n';
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.' ),
11
  import edit from './edit';
12
  import './style.scss';
13
 
14
+ if ( 'wp_template_part' !== fullSiteEditing.editorPostType ) {
15
  registerBlockType( 'a8c/template', {
16
  title: __( 'Template Part' ),
17
  description: __( 'Display a template part.' ),
full-site-editing/blocks/template/index.php CHANGED
@@ -16,7 +16,6 @@ function render_template_block( $attributes ) {
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'] : '';
@@ -25,8 +24,11 @@ function render_template_block( $attributes ) {
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
16
  return;
17
  }
18
 
 
19
  $template = get_post( $attributes['templateId'] );
20
 
21
  $align = isset( $attributes['align'] ) ? ' align' . $attributes['align'] : '';
24
  ob_start();
25
  ?>
26
 
27
+ <div class="template-part<?php echo esc_attr( $align ); ?>">
28
+ <?php
29
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
30
+ echo apply_filters( 'the_content', get_the_content() );
31
+ ?>
32
  </div><!-- .template-part -->
33
 
34
  <?php
full-site-editing/blocks/template/style.scss CHANGED
@@ -1,3 +1,11 @@
 
 
 
 
 
 
 
 
1
  .template-block.alignfull {
2
  padding: 0 12px;
3
  }
@@ -19,3 +27,12 @@
19
  display: table;
20
  }
21
  }
 
 
 
 
 
 
 
 
 
1
+ .template-block {
2
+ min-height: 200px;
3
+
4
+ &:hover .template-block__overlay {
5
+ display: flex;
6
+ }
7
+ }
8
+
9
  .template-block.alignfull {
10
  padding: 0 12px;
11
  }
27
  display: table;
28
  }
29
  }
30
+
31
+ .template-block__overlay {
32
+ display: none;
33
+ position: absolute;
34
+ top: 0;
35
+ left: 0;
36
+ width: 100%;
37
+ height: 100%;
38
+ }
full-site-editing/class-full-site-editing.php CHANGED
@@ -16,6 +16,8 @@ class Full_Site_Editing {
16
  */
17
  private static $instance = null;
18
 
 
 
19
  /**
20
  * Full_Site_Editing constructor.
21
  */
@@ -25,6 +27,23 @@ class Full_Site_Editing {
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
  /**
@@ -156,6 +175,46 @@ class Full_Site_Editing {
156
  )
157
  );
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  register_taxonomy(
160
  'wp_template_part_type',
161
  'wp_template_part',
@@ -247,7 +306,8 @@ class Full_Site_Editing {
247
  'fullSiteEditing',
248
  array(
249
  'editorPostType' => get_current_screen()->post_type,
250
- 'featureFlags' => $feature_flags->get_flags(),
 
251
  )
252
  );
253
 
@@ -257,7 +317,7 @@ class Full_Site_Editing {
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
  }
@@ -266,6 +326,19 @@ class Full_Site_Editing {
266
  * Register blocks.
267
  */
268
  public function register_blocks() {
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  register_block_type(
270
  'a8c/post-content',
271
  array(
@@ -273,12 +346,32 @@ class Full_Site_Editing {
273
  )
274
  );
275
 
 
 
 
 
 
 
 
276
  register_block_type(
277
  'a8c/template',
278
  array(
279
  'render_callback' => 'render_template_block',
280
  )
281
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  }
283
 
284
  /**
@@ -302,4 +395,163 @@ class Full_Site_Editing {
302
  // Setting this to `public` will allow it to be found in the search endpoint.
303
  $post_type->public = true;
304
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
16
  */
17
  private static $instance = null;
18
 
19
+ private $template_post_types = array( 'wp_template', 'wp_template_part' );
20
+
21
  /**
22
  * Full_Site_Editing constructor.
23
  */
27
  add_action( 'init', array( $this, 'register_meta_template_id' ) );
28
  add_action( 'rest_api_init', array( $this, 'allow_searching_for_templates' ) );
29
  add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_script_and_style' ), 100 );
30
+
31
+ add_action(
32
+ 'wp_head',
33
+ function() {
34
+ ob_start( 'a8c_fse_replace_template_parts' );
35
+ }
36
+ );
37
+
38
+ add_action(
39
+ 'wp_footer',
40
+ function() {
41
+ ob_end_flush();
42
+ }
43
+ );
44
+
45
+ add_action( 'the_post', array( $this, 'merge_template_and_post' ) );
46
+ add_filter( 'wp_insert_post_data', array( $this, 'remove_template_components' ), 10, 2 );
47
  }
48
 
49
  /**
175
  )
176
  );
177
 
178
+ register_taxonomy(
179
+ 'wp_template_type',
180
+ 'wp_template',
181
+ array(
182
+ 'labels' => array(
183
+ 'name' => _x( 'Template Types', 'taxonomy general name', 'full-site-editing' ),
184
+ 'singular_name' => _x( 'Template Type', 'taxonomy singular name', 'full-site-editing' ),
185
+ 'menu_name' => _x( 'Template Types', 'admin menu', 'full-site-editing' ),
186
+ 'all_items' => __( 'All Template Types', 'full-site-editing' ),
187
+ 'edit_item' => __( 'Edit Template Type', 'full-site-editing' ),
188
+ 'view_item' => __( 'View Template Type', 'full-site-editing' ),
189
+ 'update_item' => __( 'Update Template Type', 'full-site-editing' ),
190
+ 'add_new_item' => __( 'Add New Template Type', 'full-site-editing' ),
191
+ 'new_item_name' => __( 'New Template Type', 'full-site-editing' ),
192
+ 'parent_item' => __( 'Parent Template Type', 'full-site-editing' ),
193
+ 'parent_item_colon' => __( 'Parent Template Type:', 'full-site-editing' ),
194
+ 'search_items' => __( 'Search Template Types', 'full-site-editing' ),
195
+ 'not_found' => __( 'No template types found.', 'full-site-editing' ),
196
+ 'back_to_items' => __( 'Back to template types', 'full-site-editing' ),
197
+ ),
198
+ 'public' => false,
199
+ 'publicly_queryable' => true,
200
+ 'show_ui' => true,
201
+ 'show_in_menu' => false,
202
+ 'show_in_nav_menu' => false,
203
+ 'show_in_rest' => true,
204
+ 'rest_base' => 'template_types',
205
+ 'show_tagcloud' => false,
206
+ 'show_admin_column' => true,
207
+ 'hierarchical' => true,
208
+ 'rewrite' => false,
209
+ 'capabilities' => array(
210
+ 'manage_terms' => 'edit_theme_options',
211
+ 'edit_terms' => 'edit_theme_options',
212
+ 'delete_terms' => 'edit_theme_options',
213
+ 'assign_terms' => 'edit_theme_options',
214
+ ),
215
+ )
216
+ );
217
+
218
  register_taxonomy(
219
  'wp_template_part_type',
220
  'wp_template_part',
306
  'fullSiteEditing',
307
  array(
308
  'editorPostType' => get_current_screen()->post_type,
309
+ 'featureFlags' => $feature_flags->get_flags(),
310
+ 'closeButtonUrl' => $this->get_close_button_url(),
311
  )
312
  );
313
 
317
  wp_enqueue_style(
318
  'a8c-full-site-editing-style',
319
  plugins_url( 'dist/' . $style_file, __FILE__ ),
320
+ 'wp-edit-post',
321
  filemtime( plugin_dir_path( __FILE__ ) . 'dist/' . $style_file )
322
  );
323
  }
326
  * Register blocks.
327
  */
328
  public function register_blocks() {
329
+ register_block_type(
330
+ 'a8c/navigation-menu',
331
+ array(
332
+ 'attributes' => [
333
+ 'themeLocation' => [
334
+ 'default' => 'main-1',
335
+ 'type' => 'string',
336
+ ],
337
+ ],
338
+ 'render_callback' => 'render_navigation_menu_block',
339
+ )
340
+ );
341
+
342
  register_block_type(
343
  'a8c/post-content',
344
  array(
346
  )
347
  );
348
 
349
+ register_block_type(
350
+ 'a8c/site-description',
351
+ array(
352
+ 'render_callback' => 'render_site_description_block',
353
+ )
354
+ );
355
+
356
  register_block_type(
357
  'a8c/template',
358
  array(
359
  'render_callback' => 'render_template_block',
360
  )
361
  );
362
+
363
+ register_block_type(
364
+ 'a8c/site-logo',
365
+ array(
366
+ 'attributes' => array(
367
+ 'editorPreview' => array(
368
+ 'type' => 'boolean',
369
+ 'default' => false,
370
+ ),
371
+ ),
372
+ 'render_callback' => 'render_site_logo',
373
+ )
374
+ );
375
  }
376
 
377
  /**
395
  // Setting this to `public` will allow it to be found in the search endpoint.
396
  $post_type->public = true;
397
  }
398
+
399
+ /**
400
+ * Returns the URL for the Gutenberg close button.
401
+ *
402
+ * In some cases we want to override the default value which would take us to post listing
403
+ * for a given post type. For example, when navigating back from Header, we want to show the
404
+ * parent page editing view, and not the Template Part CPT list.
405
+ *
406
+ * @return null|string Override URL string if it should be inserted, or null otherwise.
407
+ */
408
+ public function get_close_button_url() {
409
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
410
+ if ( ! isset( $_GET['fse_parent_post'] ) ) {
411
+ return null;
412
+ }
413
+
414
+ $parent_post_id = absint( $_GET['fse_parent_post'] );
415
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
416
+
417
+ if ( empty( $parent_post_id ) ) {
418
+ return null;
419
+ }
420
+
421
+ $close_button_url = get_edit_post_link( $parent_post_id );
422
+
423
+ /**
424
+ * Filter the Gutenberg's close button URL when editing Template Part CPTs.
425
+ *
426
+ * @since 0.1
427
+ *
428
+ * @param string Current close button URL.
429
+ */
430
+ $close_button_url = apply_filters( 'a8c_fse_close_button_link', $close_button_url );
431
+
432
+ return $close_button_url;
433
+ }
434
+
435
+ /** This will merge the post content with the post template, modifiying the
436
+ * $post parameter.
437
+ *
438
+ * @param WP_Post $post
439
+ */
440
+ public function merge_template_and_post( $post ) {
441
+ //bail if not a REST API Request
442
+ if ( defined( 'REST_REQUEST' ) && ! REST_REQUEST ) {
443
+ return;
444
+ }
445
+
446
+ // bail if the post type is one of the template post types
447
+ if ( in_array( get_post_type( $post->ID ), $this->template_post_types ) ) {
448
+ return;
449
+ }
450
+
451
+ $template_id = get_post_meta( $post->ID, '_wp_template_id', true );
452
+ //bail if the post has no tempalte id assigned
453
+ if ( ! $template_id ) {
454
+ return;
455
+ }
456
+
457
+ $template = get_post( $template_id );
458
+ $wrapped_post_content = sprintf( '<!-- wp:a8c/post-content -->%s<!-- /wp:a8c/post-content -->', $post->post_content );
459
+ $post->post_content = str_replace( '<!-- wp:a8c/post-content /-->', $wrapped_post_content, $template->post_content );
460
+ }
461
+
462
+ /**
463
+ * This will extract the inner blocks of the post content and
464
+ * serialize them back to HTML for saving.
465
+ *
466
+ * @param array $data An array of slashed post data.
467
+ * @param array $postarr An array of sanitized, but otherwise unmodified post data.
468
+ */
469
+ public function remove_template_components( $data, $postarr ) {
470
+ // bail if the post type is one of the template post types
471
+ if ( in_array( $postarr['post_type'], $this->template_post_types ) ) {
472
+ return $data;
473
+ }
474
+
475
+ $post_content = wp_unslash( $data['post_content'] );
476
+
477
+ //bail if post content has no blocks
478
+ if( ! has_blocks( $post_content ) ) {
479
+ return $data;
480
+ }
481
+
482
+ $post_content_blocks = parse_blocks( $post_content );
483
+ $post_content_key = array_search( 'a8c/post-content', array_column( $post_content_blocks, 'blockName' ) );
484
+
485
+ // bail if no post content block found
486
+ if( ! $post_content_key ) {
487
+ return $data;
488
+ }
489
+
490
+ $data['post_content'] = wp_slash( serialize_blocks( $post_content_blocks[ $post_content_key ]['innerBlocks'] ) );
491
+ return $data;
492
+ }
493
+ }
494
+
495
+ if ( ! function_exists( 'serialize_block' ) ) {
496
+ /**
497
+ * Renders an HTML-serialized form of a block object
498
+ * from https://core.trac.wordpress.org/ticket/47375
499
+ *
500
+ * should be available since WordPress 5.3.0
501
+ *
502
+ * @param array $block The block being rendered.
503
+ * @return string The HTML-serialized form of the block
504
+ */
505
+ function serialize_block( $block ) {
506
+ // Non-block content has no block name.
507
+ if ( null === $block['blockName'] ) {
508
+ return $block['innerHTML'];
509
+ }
510
+
511
+ $unwanted = array( '--', '<', '>', '&', '\"' );
512
+ $wanted = array( '\u002d\u002d', '\u003c', '\u003e', '\u0026', '\u0022' );
513
+
514
+ $name = 0 === strpos( $block['blockName'], 'core/' ) ? substr( $block['blockName'], 5 ) : $block['blockName'];
515
+ $has_attrs = ! empty( $block['attrs'] );
516
+ $attrs = $has_attrs ? str_replace( $unwanted, $wanted, wp_json_encode( $block['attrs'] ) ) : '';
517
+
518
+ // Early abort for void blocks holding no content.
519
+ if ( empty( $block['innerContent'] ) ) {
520
+ return $has_attrs
521
+ ? "<!-- wp:{$name} {$attrs} /-->"
522
+ : "<!-- wp:{$name} /-->";
523
+ }
524
+
525
+ $output = $has_attrs
526
+ ? "<!-- wp:{$name} {$attrs} -->\n"
527
+ : "<!-- wp:{$name} -->\n";
528
+
529
+ $inner_block_index = 0;
530
+ foreach ( $block['innerContent'] as $chunk ) {
531
+ $output .= null === $chunk
532
+ ? serialize_block( $block['innerBlocks'][ $inner_block_index++ ] )
533
+ : $chunk;
534
+
535
+ $output .= "\n";
536
+ }
537
+
538
+ $output .= "<!-- /wp:{$name} -->";
539
+
540
+ return $output;
541
+ }
542
+ }
543
+
544
+ if ( ! function_exists( 'serialize_blocks' ) ) {
545
+ /**
546
+ * Renders an HTML-serialized form of a list of block objects
547
+ * from https://core.trac.wordpress.org/ticket/47375
548
+ *
549
+ * should be available since WordPress 5.3.0
550
+ *
551
+ * @param array $blocks The list of parsed block objects
552
+ * @return string The HTML-serialized form of the list of blocks
553
+ */
554
+ function serialize_blocks( $blocks ) {
555
+ return implode( "\n\n", array_map( 'serialize_block', $blocks ) );
556
+ }
557
  }
full-site-editing/dist/full-site-editing.css CHANGED
@@ -1 +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}
1
+ .wp-block-a8c-navigation-menu .main-navigation{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:1.125em;font-weight:700;letter-spacing:-.02em;line-height:1.2;pointer-events:none;-webkit-font-smoothing:antialiased}.wp-block-a8c-navigation-menu .main-navigation .main-menu{display:inline-block;margin:0;padding:0}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li{color:#0073aa;display:inline;position:relative}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li>a{font-weight:700;color:#0073aa;margin-right:.5rem}.main-navigation .main-menu>li:last-child.menu-item-has-children .submenu-expand,.wp-block-a8c-navigation-menu .main-navigation .main-menu>li:last-child>a{margin-right:0}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children>a{margin-right:.125rem}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children{display:inline-block;position:inherit}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children .submenu-expand{display:inline-block;margin-right:.25rem}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children .submenu-expand svg{position:relative;top:.3rem}.main-navigation .main-menu>li>a:hover+svg,.wp-block-a8c-navigation-menu .main-navigation .main-menu>li>a:hover{color:#005177}.wp-block-a8c-navigation-menu .main-navigation svg{transition:fill .12s ease-in-out;fill:currentColor}.wp-block-a8c-navigation-menu .main-navigation a{text-decoration:none}.wp-block-a8c-navigation-menu .main-navigation button{display:inline-block;border:none;padding:0;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:.88889em;font-weight:700;line-height:1.2;text-decoration:none;vertical-align:bottom;background:transparent;color:inherit;cursor:pointer;transition:background .25s ease-in-out,transform .15s ease;-webkit-appearance:none;-moz-appearance:none}.wp-block-a8c-navigation-menu .main-menu-more{display:none}.wp-block-a8c-navigation-menu .social-navigation{line-height:1.25;margin-top:.5rem;text-align:left}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu{content:"";display:inline-block;margin:0;padding:0}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li{display:inline-block;vertical-align:bottom;vertical-align:-webkit-baseline-middle;list-style:none}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li a svg{display:block;width:32px;height:32px;transform:translateZ(0)}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu{display:inline;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:.71111em;padding-left:0}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu li{display:inline;margin-right:1rem}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu a{text-decoration:none;color:#767676}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu a:hover{text-decoration:none;color:#0073aa}.editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a,.editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a:hover{color:#555d66}.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}.block-editor .wp-block-a8c-site-description,.block-editor .wp-block-a8c-site-description:focus{display:inline;color:#767676;font-size:1.125em;font-weight:400;letter-spacing:-.01em;margin:0}.template-block{min-height:200px}.template-block:hover .template-block__overlay{display:flex}.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}.template-block__overlay{display:none;position:absolute;top:0;left:0;width:100%;height:100%}.wp-block-a8c-site-logo{pointer-events:none}
full-site-editing/dist/full-site-editing.deps.json CHANGED
@@ -1 +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"]
1
+ ["lodash","wp-api-fetch","wp-block-editor","wp-blocks","wp-components","wp-compose","wp-data","wp-dom-ready","wp-edit-post","wp-editor","wp-element","wp-i18n","wp-plugins","wp-url"]
full-site-editing/dist/full-site-editing.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(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
@@ -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 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})}]));
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 i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.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 i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));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=42)}([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=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.data},function(e,t){e.exports=wp.blocks},function(e,t){e.exports=wp.editor},function(e,t){e.exports=function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}},function(e,t){e.exports=wp.url},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t){function n(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}e.exports=function(e,t,o){return t&&n(e.prototype,t),o&&n(e,o),e}},function(e,t,n){var o=n(35),i=n(9);e.exports=function(e,t){return!t||"object"!==o(t)&&"function"!=typeof t?i(e):t}},function(e,t){function n(t){return e.exports=n=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},n(t)}e.exports=n},function(e,t,n){var o=n(36);e.exports=function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&o(e,t)}},function(e,t,n){var o;
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 i(){for(var e=[],t=0;t<arguments.length;t++){var o=arguments[t];if(o){var r=typeof o;if("string"===r||"number"===r)e.push(o);else if(Array.isArray(o)&&o.length){var c=i.apply(null,o);c&&e.push(c)}else if("object"===r)for(var a in o)n.call(o,a)&&o[a]&&e.push(a)}}return e.join(" ")}e.exports?(i.default=i,e.exports=i):void 0===(o=function(){return i}.apply(t,[]))||(e.exports=o)}()},function(e,t){e.exports=wp.blockEditor},function(e,t){e.exports=wp.apiFetch},function(e,t){e.exports=wp.domReady},function(e,t){e.exports=wp.editPost},function(e,t,n){},function(e,t,n){var o=n(28),i=n(29),r=n(30);e.exports=function(e,t){return o(e)||i(e,t)||r()}},function(e,t,n){var o=n(5);e.exports=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),i.forEach(function(t){o(e,t,n[t])})}return e}},function(e,t){function n(e,t,n,o,i,r,c){try{var a=e[r](c),l=a.value}catch(s){return void n(s)}a.done?t(l):Promise.resolve(l).then(o,i)}e.exports=function(e){return function(){var t=this,o=arguments;return new Promise(function(i,r){var c=e.apply(t,o);function a(e){n(c,i,r,a,l,"next",e)}function l(e){n(c,i,r,a,l,"throw",e)}a(void 0)})}}},function(e,t){e.exports=wp.plugins},function(e,t,n){},,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,i=!1,r=void 0;try{for(var c,a=e[Symbol.iterator]();!(o=(c=a.next()).done)&&(n.push(c.value),!t||n.length!==t);o=!0);}catch(l){i=!0,r=l}finally{try{o||null==a.return||a.return()}finally{if(i)throw r}}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){function n(e){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(t){return"function"==typeof Symbol&&"symbol"===n(Symbol.iterator)?e.exports=o=function(e){return n(e)}:e.exports=o=function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":n(e)},o(t)}e.exports=o},function(e,t){function n(t,o){return e.exports=n=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},n(t,o)}e.exports=n},function(e,t,n){},,,function(e,t,n){},,function(e,t,n){"use strict";n.r(t);var o=n(0),i=n(7),r=n(1),c=n(2),a=n(8),l=n(10),s=function(e){var t=e.attributes,n=Object(l.addQueryArgs)("customize.php",{"autofocus[panel]":"nav_menus",return:window.location.href});return Object(o.createElement)(o.Fragment,null,Object(o.createElement)(a.BlockControls,null,Object(o.createElement)(c.Toolbar,{className:"wp-block-a8c-navigation-menu-toolbar"},Object(o.createElement)(c.IconButton,{icon:"edit",label:Object(r.__)("Edit Menu"),href:n,className:"components-toolbar__control"}))),Object(o.createElement)(c.ServerSideRender,{attributes:t,block:"a8c/navigation-menu",className:"wp-block-a8c-navigation-menu"}))},u=(n(26),Object(o.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24"},Object(o.createElement)("path",{fill:"none",d:"M0 0h24v24H0V0z"}),Object(o.createElement)("path",{d:"M12 7.27l4.28 10.43-3.47-1.53-.81-.36-.81.36-3.47 1.53L12 7.27M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71L12 2z"})));Object(i.registerBlockType)("a8c/navigation-menu",{title:Object(r.__)("Navigation Menu"),description:Object(r.__)("Visual placeholder for site-wide navigation and menus."),icon:u,category:"layout",supports:{html:!1,multiple:!1,reusable:!1},attributes:{themeLocation:{type:"string",default:"main-1"}},edit:s,save:function(){return null}});var p=n(17),b=n(5),d=n.n(b),f=n(16),m=n.n(f),g=n(3),O=n(4),h=n(6),j=n(22),y=n.n(j),v=n(23),_=n.n(v),S=n(24),E=n.n(S),w=n(18),P=n.n(w),x=(n(31),Object(g.debounce)(function(){var e=E()(regeneratorRuntime.mark(function e(t,n,o){var i;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return o({loading:!0,showSuggestions:!0,suggestions:[]}),e.next=3,P()({path:Object(l.addQueryArgs)("/wp/v2/search",_()({context:"embed",per_page:20,search:t},!!n&&{subtype:n}))});case 3:i=e.sent,o({loading:!1,showSuggestions:!0,suggestions:i});case 5:case"end":return e.stop()}},e)}));return function(t,n,o){return e.apply(this,arguments)}}(),200)),k=Object(O.withState)({loading:!1,showSuggestions:!1,suggestions:[]})(function(e){var t=e.initialValue,n=e.loading,i=e.onSelectPost,a=e.postType,l=e.setState,s=e.showSuggestions,u=e.suggestions,p=Object(o.useState)(t),b=y()(p,2),d=b[0],f=b[1],m=function(e){return function(){var t=function(e,t,n){var o=e.id,i=e.title,r=e.subtype;return t({loading:!1,showSuggestions:!1,suggestions:[]}),n(i),{id:o,type:r}}(e,l,f);i(t)}};return Object(o.createElement)("div",{className:"a8c-post-autocomplete"},Object(o.createElement)(c.TextControl,{autoComplete:"off",onChange:function(e){f(e),e.length<2?l({loading:!1,showSuggestions:!1}):x(e,a,l)},placeholder:Object(r.__)("Type to search"),type:"search",value:d}),n&&Object(o.createElement)(c.Spinner,null),s&&!!u.length&&Object(o.createElement)(c.Popover,{focusOnMount:!1,noArrow:!0,position:"bottom"},Object(o.createElement)("div",{className:"a8c-post-autocomplete__suggestions"},Object(g.map)(u,function(e){return Object(o.createElement)(c.Button,{isLarge:!0,isLink:!0,key:e.id,onClick:m(e)},e.title)}))))}),T=Object(O.compose)(Object(O.withState)({isEditing:!1,selectedPostId:void 0,selectedPostType:void 0}),Object(h.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,i=e.selectedPost,l=e.setState,s=t.align,u=!n||!!i,p=n||!i,b=!n&&!!i;return Object(o.createElement)(o.Fragment,null,u&&Object(o.createElement)(a.BlockControls,null,Object(o.createElement)(c.Toolbar,null,Object(o.createElement)(c.IconButton,{className:m()("components-icon-button components-toolbar__control",{"is-active":n}),label:Object(r.__)("Change Preview"),onClick:function(){return l({isEditing:!n})},icon:"edit"}))),Object(o.createElement)("div",{className:m()("post-content-block",d()({},"align".concat(s),s))},p&&Object(o.createElement)(c.Placeholder,{icon:"layout",label:Object(r.__)("Content Slot"),instructions:Object(r.__)("Placeholder for a post or a page.")},Object(o.createElement)("div",{className:"post-content-block__selector"},Object(o.createElement)("div",null,Object(r.__)("Select something to preview:")),Object(o.createElement)(k,{initialValue:Object(g.get)(i,["title","rendered"]),onSelectPost:function(e){var t=e.id,n=e.type;l({isEditing:!1,selectedPostId:t,selectedPostType:n})},postType:["page","post"]}),!!i&&Object(o.createElement)("a",{href:"?post=".concat(i.id,"&action=edit")},Object(r.sprintf)(Object(r.__)('Edit "%s"'),Object(g.get)(i,["title","rendered"],""))))),b&&Object(o.createElement)(o.RawHTML,{className:"post-content-block__preview"},Object(g.get)(i,["content","rendered"]))))}),C=(n(33),"wp_template"===fullSiteEditing.editorPostType);Object(i.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:C?T:function(){return Object(o.createElement)(p.InnerBlocks,null)},save:C?function(){return null}:function(){return Object(o.createElement)(p.InnerBlocks.Content,null)}});var B=n(11),N=n.n(B),I=n(12),R=n.n(I),D=n(13),L=n.n(D),M=n(14),A=n.n(M),U=n(9),F=n.n(U),z=n(15),V=n.n(z),H=function(e){function t(){var e,n;N()(this,t);for(var o=arguments.length,i=new Array(o),c=0;c<o;c++)i[c]=arguments[c];return n=L()(this,(e=A()(t)).call.apply(e,[this].concat(i))),d()(F()(n),"state",{description:Object(r.__)("Site description loading…"),initialDescription:""}),d()(F()(n),"revertDescription",function(){return n.setState({description:n.state.initialDescription})}),d()(F()(n),"updateInitialDescription",function(){return n.setState({initialDescription:n.state.description})}),n}return V()(t,e),R()(t,[{key:"componentDidMount",value:function(){var e=this,t=this.props.noticeOperations;return P()({path:"/wp/v2/settings"}).then(function(t){var n=t.description;return e.setState({initialDescription:n,description:n})}).catch(function(e){var n=e.message;t.createErrorNotice(n)})}},{key:"componentDidUpdate",value:function(e){var t=this,n=this.state,o=n.description,i=n.initialDescription,r=this.props,c=r.shouldUpdateSiteOption,a=r.noticeOperations,l=r.isSelected,s=o&&o.trim()===i.trim(),u=!o||0===o.trim().length;!l&&e.isSelected&&u&&this.revertDescription(),c&&!s&&!e.shouldUpdateSiteOption&&c&&P()({path:"/wp/v2/settings",method:"POST",data:{description:o}}).then(function(){return t.updateInitialDescription()}).catch(function(e){var n=e.message;a.createErrorNotice(n),t.revertDescription()})}},{key:"render",value:function(){var e=this,t=this.props,n=t.className,i=t.noticeUI,c=this.state.description;return Object(o.createElement)(o.Fragment,null,i,Object(o.createElement)(p.PlainText,{className:n,value:c,onChange:function(t){return e.setState({description:t})},placeholder:Object(r.__)("Site Description"),"aria-label":Object(r.__)("Site Description")}))}}]),t}(o.Component),Q=Object(O.compose)([Object(h.withSelect)(function(e){var t=e("core/editor"),n=t.isSavingPost,o=t.isPublishingPost,i=t.isAutosavingPost,r=t.isCurrentPostPublished;return{shouldUpdateSiteOption:(n()&&r()||o())&&!i()}}),c.withNotices])(H);n(37);Object(i.registerBlockType)("a8c/site-description",{title:Object(r.__)("Site Description2"),description:Object(r.__)("Site description, also known as the tagline."),icon:"layout",category:"layout",supports:{html:!1,multiple:!1,reusable:!1},edit:Q,save:function(){return null}});n(21);var q=Object(O.compose)(Object(h.withSelect)(function(e,t){var n=t.attributes,o=e("core").getEntityRecord,i=e("core/editor").getCurrentPostId,r=n.templateId;return{currentPostId:i(),template:r&&o("postType","wp_template_part",r)}}),Object(O.withState)({isEditing:!1}))(function(e){var t=e.attributes,n=e.currentPostId,i=e.isEditing,l=e.template,s=e.setAttributes,u=e.setState,p=t.align,b=t.templateId,f=!i||!!b,O=i||!b,h=!i&&!!b,j="wp_template"===fullSiteEditing.editorPostType;return Object(o.createElement)(o.Fragment,null,f&&j&&Object(o.createElement)(a.BlockControls,null,Object(o.createElement)(c.Toolbar,null,Object(o.createElement)(c.IconButton,{className:m()("components-icon-button components-toolbar__control",{"is-active":i}),label:Object(r.__)("Change Template Part"),onClick:function(){return u({isEditing:!i})},icon:"edit"}))),Object(o.createElement)("div",{className:m()("template-block",d()({},"align".concat(p),p))},O&&Object(o.createElement)(c.Placeholder,{icon:"layout",label:Object(r.__)("Template Part"),instructions:Object(r.__)("Select a template part to display")},Object(o.createElement)("div",{className:"template-block__selector"},Object(o.createElement)(k,{initialValue:Object(g.get)(l,["title","rendered"]),onSelectPost:function(e){var t=e.id;u({isEditing:!1}),s({templateId:t})},postType:"wp_template_part"}),!!l&&Object(o.createElement)("a",{href:"?post=".concat(b,"&action=edit&fse_parent_post=").concat(n)},Object(r.sprintf)(Object(r.__)('Edit "%s"'),Object(g.get)(l,["title","rendered"],""))))),h&&Object(o.createElement)(o.Fragment,null,Object(o.createElement)(o.RawHTML,{className:"template-block__content"},Object(g.get)(l,["content","rendered"])),!j&&Object(o.createElement)(c.Placeholder,{className:"template-block__overlay",instructions:Object(r.__)("This block is part of your site template and may appear on multiple pages.")},Object(o.createElement)(c.Button,{href:"?post=".concat(b,"&action=edit&fse_parent_post=").concat(n),isDefault:!0},Object(r.sprintf)(Object(r.__)("Edit %s"),Object(g.get)(l,["title","rendered"],"")))))))});"wp_template_part"!==fullSiteEditing.editorPostType&&Object(i.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:q,save:function(){return null}});var G=function(e){var t=e.className;return Object(o.createElement)(o.Fragment,null,Object(o.createElement)(a.BlockControls,null,Object(o.createElement)(c.Toolbar,null,Object(o.createElement)(c.IconButton,{className:"components-toolbar__control",icon:"edit",label:Object(r.__)("Edit Site Logo"),onClick:function(){var e=Object(l.addQueryArgs)("customize.php",{"autofocus[section]":"title_tagline",return:window.location.href});window.location.href=e}}))),Object(o.createElement)(c.ServerSideRender,{className:t,block:"a8c/site-logo",attributes:{editorPreview:!0}}))};n(40);Object(i.registerBlockType)("a8c/site-logo",{title:Object(r.__)("Site Logo"),description:Object(r.__)("Site Logo"),icon:"format-image",category:"layout",keywords:[Object(r.__)("logo"),Object(r.__)("icon"),Object(r.__)("site")],edit:G,save:function(){return null}});var J=n(20),K=n(25),W=Object(O.compose)(Object(h.withDispatch)(function(e){return{setTemplateId:function(t){return e("core/editor").editPost({meta:{_wp_template_id:t}})}}}),Object(h.withSelect)(function(e){var t=e("core"),n=t.canUser,o=t.getEntityRecord,i=Object(g.get)(e("core/editor").getEditedPostAttribute("meta"),"_wp_template_id");return{canUserUpdateSettings:n("update","settings"),selectedTemplate:i&&o("postType","wp_template",i)}}))(function(e){var t=e.canUserUpdateSettings,n=e.setTemplateId,i=e.selectedTemplate;if(!t)return null;return Object(o.createElement)(o.Fragment,null,Object(o.createElement)(J.PluginSidebarMoreMenuItem,{target:"fse-template-sidebar",icon:"layout"},Object(r.__)("Template")),Object(o.createElement)(J.PluginSidebar,{icon:"layout",name:"fse-template-sidebar",title:Object(r.__)("Template")},Object(o.createElement)(c.PanelBody,null,Object(r.__)("Select a template"),Object(o.createElement)(k,{initialValue:Object(g.get)(i,["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:W});var X=n(19),Y=n.n(X);Y()(function(){if("wp_template_part"===fullSiteEditing.editorPostType&&fullSiteEditing.closeButtonUrl){var e=document.querySelector(".edit-post-fullscreen-mode-close__toolbar a");e&&(e.href=fullSiteEditing.closeButtonUrl)}});var Z=function(e){function t(){return N()(this,t),L()(this,A()(t).apply(this,arguments))}return V()(t,e),R()(t,[{key:"render",value:function(){var e=this.props,t=e.onSave,n=e.onClose,i=e.isBusy,a=e.disabled;return Object(o.createElement)("div",{className:"edit-post-layout"},Object(o.createElement)("div",{className:"editor-post-publish-panel"},Object(o.createElement)("div",{className:"editor-post-publish-panel__header"},Object(o.createElement)("div",{className:"editor-post-publish-panel__header-publish-button"},Object(o.createElement)(c.Button,{isPrimary:!0,isLarge:!0,isBusy:i,onClick:t,disabled:a},Object(r.__)("Publish")),Object(o.createElement)("span",{className:"editor-post-publish-panel__spacer"})),Object(o.createElement)(c.IconButton,{"aria-expanded":!0,onClick:n,icon:"no-alt",label:Object(r.__)("Close panel")})),Object(o.createElement)("div",{className:"editor-post-publish-panel__prepublish"},Object(o.createElement)("p",null,Object(o.createElement)("strong",null,Object(r.__)("Are you ready to publish?"))),Object(o.createElement)("p",null,Object(r.__)("Changes you publish will update all pages with this template part.")))))}}]),t}(o.Component),$={buttonStyle:{visibility:"hidden"},isPanelOpen:!1},ee=function(e){function t(e){var n;return N()(this,t),n=L()(this,A()(t).call(this,e)),d()(F()(n),"onPublish",function(){n.togglePanel(),n.getOriginalButton().click()}),d()(F()(n),"togglePanel",function(){n.setState({isPanelOpen:!n.state.isPanelOpen})}),n.onResize=Object(g.debounce)(n.onResize,100),n.state=$,n.onResize(),n}return V()(t,e),R()(t,[{key:"componentDidUpdate",value:function(e,t){var n=this;e.isFullScreen!==t.isFullScreen&&setTimeout(function(){return n.onResize()},1)}},{key:"getOriginalButton",value:function(){return document.querySelector(".edit-post-header .editor-post-publish-button")}},{key:"onResize",value:function(){var e=this.getOriginalButton(),t=$.buttonStyle;if(Object(g.isNil)(e)||!("getBoundingClientRect"in e))return this.setState({buttonStyle:t});var n=e.getBoundingClientRect();t={height:"33px",position:"fixed",zIndex:"10001",top:n.top,left:n.x},window.matchMedia("(min-width: 600px)").matches||(t.paddingLeft="5px",t.paddingRight="5px"),this.setState({buttonStyle:t})}},{key:"getHidingCss",value:function(){return".edit-post-header .editor-post-publish-button {\n\t\t\tvisibility: hidden !important;\n\t\t}"}},{key:"render",value:function(){if(!this.shouldRender())return null;var e=this.props,t=e.isSaving,n=e.isSaveable,i=e.isPostSavingLocked,a=e.isPublishable,l=t||!n||i||!a;return Object(o.createElement)(o.Fragment,null,Object(o.createElement)(c.Button,{onClick:this.togglePanel,isPrimary:!0,isLarge:!0,style:this.state.buttonStyle,disabled:l,isBusy:this.isSaving},Object(r.__)("Update")),this.state.isPanelOpen&&Object(o.createElement)(Z,{isBusy:this.isSaving,onClose:this.togglePanel,onSave:this.onPublish,disabled:l}),Object(o.createElement)("style",null,this.getHidingCss()))}},{key:"shouldRender",value:function(){var e=this.props,t=e.isPublished,n=e.isPublishable,o=e.isSaveable;return!!(t&&n&&o)}}]),t}(o.Component),te=Object(O.compose)([Object(h.withSelect)(function(e){var t=e("core/editor"),n=t.isSavingPost,o=t.isCurrentPostPublished,i=t.isEditedPostSaveable,r=t.isEditedPostPublishable,c=t.isPostSavingLocked,a=t.getCurrentPost;return{isSaving:n(),isSaveable:i(),isPostSavingLocked:c(),isPublishable:r(),isPublished:o(),hasPublishAction:Object(g.get)(a(),["_links","wp:action-publish"],!1),isFullScreen:e("core/edit-post").isFeatureActive("fullscreenMode")}}),Object(O.withGlobalEvents)({resize:"onResize"})])(ee);Y()(function(){if("wp_template_part"===fullSiteEditing.editorPostType){var e=document.createElement("div");e.id="template-update-confirmation",document.getElementById("wpcontent").appendChild(e),Object(o.render)(Object(o.createElement)(te,null),e)}})}]));
full-site-editing/dist/full-site-editing.rtl.css CHANGED
@@ -1 +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}
1
+ .wp-block-a8c-navigation-menu .main-navigation{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:1.125em;font-weight:700;letter-spacing:-.02em;line-height:1.2;pointer-events:none;-webkit-font-smoothing:antialiased}.wp-block-a8c-navigation-menu .main-navigation .main-menu{display:inline-block;margin:0;padding:0}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li{color:#0073aa;display:inline;position:relative}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li>a{font-weight:700;color:#0073aa;margin-left:.5rem}.main-navigation .main-menu>li:last-child.menu-item-has-children .submenu-expand,.wp-block-a8c-navigation-menu .main-navigation .main-menu>li:last-child>a{margin-left:0}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children>a{margin-left:.125rem}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children{display:inline-block;position:inherit}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children .submenu-expand{display:inline-block;margin-left:.25rem}.wp-block-a8c-navigation-menu .main-navigation .main-menu>li.menu-item-has-children .submenu-expand svg{position:relative;top:.3rem}.main-navigation .main-menu>li>a:hover+svg,.wp-block-a8c-navigation-menu .main-navigation .main-menu>li>a:hover{color:#005177}.wp-block-a8c-navigation-menu .main-navigation svg{transition:fill .12s ease-in-out;fill:currentColor}.wp-block-a8c-navigation-menu .main-navigation a{text-decoration:none}.wp-block-a8c-navigation-menu .main-navigation button{display:inline-block;border:none;padding:0;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:.88889em;font-weight:700;line-height:1.2;text-decoration:none;vertical-align:bottom;background:transparent;color:inherit;cursor:pointer;transition:background .25s ease-in-out,transform .15s ease;-webkit-appearance:none;-moz-appearance:none}.wp-block-a8c-navigation-menu .main-menu-more{display:none}.wp-block-a8c-navigation-menu .social-navigation{line-height:1.25;margin-top:.5rem;text-align:right}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu{content:"";display:inline-block;margin:0;padding:0}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li{display:inline-block;vertical-align:bottom;vertical-align:-webkit-baseline-middle;list-style:none}.wp-block-a8c-navigation-menu .social-navigation ul.social-links-menu li a svg{display:block;width:32px;height:32px;transform:translateZ(0)}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu{display:inline;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:.71111em;padding-right:0}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu li{display:inline;margin-left:1rem}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu a{text-decoration:none;color:#767676}.wp-block-a8c-navigation-menu .footer-navigation .footer-menu a:hover{text-decoration:none;color:#0073aa}.editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a,.editor-styles-wrapper .wp-block-a8c-navigation-menu-toolbar a:hover{color:#555d66}.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}.block-editor .wp-block-a8c-site-description,.block-editor .wp-block-a8c-site-description:focus{display:inline;color:#767676;font-size:1.125em;font-weight:400;letter-spacing:-.01em;margin:0}.template-block{min-height:200px}.template-block:hover .template-block__overlay{display:flex}.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}.template-block__overlay{display:none;position:absolute;top:0;right:0;width:100%;height:100%}.wp-block-a8c-site-logo{pointer-events:none}
full-site-editing/index.js CHANGED
@@ -1,6 +1,11 @@
1
  /**
2
  * Internal dependencies
3
  */
 
4
  import './blocks/post-content';
 
5
  import './blocks/template';
 
6
  import './plugins/template-selector-sidebar';
 
 
1
  /**
2
  * Internal dependencies
3
  */
4
+ import './blocks/navigation-menu';
5
  import './blocks/post-content';
6
+ import './blocks/site-description';
7
  import './blocks/template';
8
+ import './blocks/site-logo';
9
  import './plugins/template-selector-sidebar';
10
+ import './plugins/close-button-override';
11
+ import './plugins/template-update-confirmation';
full-site-editing/plugins/close-button-override/index.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global fullSiteEditing */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import domReady from '@wordpress/dom-ready';
7
+
8
+ domReady( () => {
9
+ // We only want this override when closing Template Part CPT (e.g. header) to navigate back to parent page.
10
+ if ( 'wp_template_part' !== fullSiteEditing.editorPostType ) {
11
+ return;
12
+ }
13
+
14
+ // Keep the default URL if the override hasn't been provided by the plugin.
15
+ if ( ! fullSiteEditing.closeButtonUrl ) {
16
+ return;
17
+ }
18
+
19
+ const closeButton = document.querySelector( '.edit-post-fullscreen-mode-close__toolbar a' );
20
+
21
+ if ( closeButton ) {
22
+ closeButton.href = fullSiteEditing.closeButtonUrl;
23
+ }
24
+ } );
full-site-editing/plugins/template-update-confirmation/button.js ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { Button } from '@wordpress/components';
5
+ import { Component, Fragment } from '@wordpress/element';
6
+ import { withGlobalEvents, compose } from '@wordpress/compose';
7
+ import { withSelect } from '@wordpress/data';
8
+ import { debounce, get, isNil } from 'lodash';
9
+ import { __ } from '@wordpress/i18n';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import Panel from './panel';
15
+
16
+ const initialState = {
17
+ buttonStyle: {
18
+ visibility: 'hidden',
19
+ },
20
+ isPanelOpen: false,
21
+ };
22
+
23
+ class TemplateUpdateConfirmationButton extends Component {
24
+ constructor( props ) {
25
+ super( props );
26
+ this.onResize = debounce( this.onResize, 100 );
27
+ this.state = initialState;
28
+ this.onResize();
29
+ }
30
+
31
+ componentDidUpdate( props, prevProps ) {
32
+ if ( props.isFullScreen !== prevProps.isFullScreen ) {
33
+ // this ensures the button is repositioned properly when toggling fullscreen mode
34
+ setTimeout( () => this.onResize(), 1 );
35
+ }
36
+ }
37
+
38
+ getOriginalButton() {
39
+ return document.querySelector( '.edit-post-header .editor-post-publish-button' );
40
+ }
41
+
42
+ onResize() {
43
+ const originalButton = this.getOriginalButton();
44
+ let { buttonStyle } = initialState;
45
+ if ( isNil( originalButton ) || ! ( 'getBoundingClientRect' in originalButton ) ) {
46
+ // if it's not there, might need a timeout to await it?
47
+ return this.setState( { buttonStyle } );
48
+ }
49
+ const rect = originalButton.getBoundingClientRect();
50
+ buttonStyle = {
51
+ // height doesn't line up perfectly with default styles
52
+ height: '33px',
53
+ position: 'fixed',
54
+ zIndex: '10001',
55
+ top: rect.top,
56
+ left: rect.x,
57
+ };
58
+ if ( ! window.matchMedia( '(min-width: 600px)' ).matches ) {
59
+ buttonStyle.paddingLeft = '5px';
60
+ buttonStyle.paddingRight = '5px';
61
+ }
62
+ this.setState( { buttonStyle } );
63
+ }
64
+
65
+ getHidingCss() {
66
+ return `.edit-post-header .editor-post-publish-button {
67
+ visibility: hidden !important;
68
+ }`;
69
+ }
70
+
71
+ render() {
72
+ if ( ! this.shouldRender() ) {
73
+ return null;
74
+ }
75
+ const { isSaving, isSaveable, isPostSavingLocked, isPublishable } = this.props;
76
+ const isButtonDisabled = isSaving || ! isSaveable || isPostSavingLocked || ! isPublishable;
77
+ return (
78
+ <Fragment>
79
+ <Button
80
+ onClick={ this.togglePanel }
81
+ isPrimary
82
+ isLarge
83
+ style={ this.state.buttonStyle }
84
+ disabled={ isButtonDisabled }
85
+ isBusy={ this.isSaving }
86
+ >
87
+ { __( 'Update' ) }
88
+ </Button>
89
+ { this.state.isPanelOpen && (
90
+ <Panel
91
+ isBusy={ this.isSaving }
92
+ onClose={ this.togglePanel }
93
+ onSave={ this.onPublish }
94
+ disabled={ isButtonDisabled }
95
+ />
96
+ ) }
97
+ <style>{ this.getHidingCss() }</style>
98
+ </Fragment>
99
+ );
100
+ }
101
+
102
+ shouldRender() {
103
+ const { isPublished, isPublishable, isSaveable } = this.props;
104
+ if ( ! isPublished || ! isPublishable || ! isSaveable ) {
105
+ return false;
106
+ }
107
+ return true;
108
+ }
109
+
110
+ onPublish = () => {
111
+ this.togglePanel();
112
+ this.getOriginalButton().click();
113
+ };
114
+
115
+ togglePanel = () => {
116
+ this.setState( { isPanelOpen: ! this.state.isPanelOpen } );
117
+ };
118
+ }
119
+
120
+ export default compose( [
121
+ withSelect( select => {
122
+ const {
123
+ isSavingPost,
124
+ isCurrentPostPublished,
125
+ isEditedPostSaveable,
126
+ isEditedPostPublishable,
127
+ isPostSavingLocked,
128
+ getCurrentPost,
129
+ } = select( 'core/editor' );
130
+ return {
131
+ isSaving: isSavingPost(),
132
+ isSaveable: isEditedPostSaveable(),
133
+ isPostSavingLocked: isPostSavingLocked(),
134
+ isPublishable: isEditedPostPublishable(),
135
+ isPublished: isCurrentPostPublished(),
136
+ hasPublishAction: get( getCurrentPost(), [ '_links', 'wp:action-publish' ], false ),
137
+ isFullScreen: select( 'core/edit-post' ).isFeatureActive( 'fullscreenMode' ),
138
+ };
139
+ } ),
140
+ withGlobalEvents( {
141
+ resize: 'onResize',
142
+ } ),
143
+ ] )( TemplateUpdateConfirmationButton );
full-site-editing/plugins/template-update-confirmation/index.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global fullSiteEditing */
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import domReady from '@wordpress/dom-ready';
6
+ import { render } from '@wordpress/element';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import TemplateUpdateConfirmationButton from './button';
12
+
13
+ domReady( () => {
14
+ if ( 'wp_template_part' !== fullSiteEditing.editorPostType ) {
15
+ return;
16
+ }
17
+ const element = document.createElement( 'div' );
18
+ element.id = 'template-update-confirmation';
19
+ document.getElementById( 'wpcontent' ).appendChild( element );
20
+ render( <TemplateUpdateConfirmationButton />, element );
21
+ } );
full-site-editing/plugins/template-update-confirmation/panel.js ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* eslint-disable wpcalypso/jsx-classname-namespace */
2
+ /**
3
+ * External dependencies
4
+ */
5
+ import { Component } from '@wordpress/element';
6
+ import { Button, IconButton } from '@wordpress/components';
7
+ import { __ } from '@wordpress/i18n';
8
+
9
+ export default class Panel extends Component {
10
+ render() {
11
+ const { onSave, onClose, isBusy, disabled } = this.props;
12
+ return (
13
+ <div className="edit-post-layout">
14
+ <div className="editor-post-publish-panel">
15
+ <div className="editor-post-publish-panel__header">
16
+ <div className="editor-post-publish-panel__header-publish-button">
17
+ <Button isPrimary isLarge isBusy={ isBusy } onClick={ onSave } disabled={ disabled }>
18
+ { __( 'Publish' ) }
19
+ </Button>
20
+ <span className="editor-post-publish-panel__spacer" />
21
+ </div>
22
+
23
+ <IconButton
24
+ aria-expanded={ true }
25
+ onClick={ onClose }
26
+ icon="no-alt"
27
+ label={ __( 'Close panel' ) }
28
+ />
29
+ </div>
30
+ <div className="editor-post-publish-panel__prepublish">
31
+ <p>
32
+ <strong>{ __( 'Are you ready to publish?' ) }</strong>
33
+ </p>
34
+ <p>{ __( 'Changes you publish will update all pages with this template part.' ) }</p>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ );
39
+ }
40
+ }
full-site-editing/utils/class-a8c-wp-template-data-inserter.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template data inserter file.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Class A8C_WP_Template_Data_Inserter
10
+ */
11
+ class A8C_WP_Template_Data_Inserter {
12
+ /**
13
+ * This function will be called on plugin activation hook.
14
+ */
15
+ public function insert_default_template_data() {
16
+ $header_id = wp_insert_post(
17
+ [
18
+ 'post_title' => 'Header',
19
+ 'post_content' => $this->get_header_content(),
20
+ 'post_status' => 'publish',
21
+ 'post_type' => 'wp_template_part',
22
+ 'comment_status' => 'closed',
23
+ 'ping_status' => 'closed',
24
+ ]
25
+ );
26
+
27
+ if ( ! term_exists( 'header', 'wp_template_part_type' ) ) {
28
+ wp_insert_term( 'header', 'wp_template_part_type' );
29
+ }
30
+
31
+ wp_set_object_terms( $header_id, 'header', 'wp_template_part_type' );
32
+
33
+ $footer_id = wp_insert_post(
34
+ [
35
+ 'post_title' => 'Footer',
36
+ 'post_content' => $this->get_footer_content(),
37
+ 'post_status' => 'publish',
38
+ 'post_type' => 'wp_template_part',
39
+ 'comment_status' => 'closed',
40
+ 'ping_status' => 'closed',
41
+ ]
42
+ );
43
+
44
+ if ( ! term_exists( 'footer', 'wp_template_part_type' ) ) {
45
+ wp_insert_term( 'footer', 'wp_template_part_type' );
46
+ }
47
+
48
+ wp_set_object_terms( $footer_id, 'footer', 'wp_template_part_type' );
49
+
50
+ $page_template_id = wp_insert_post(
51
+ [
52
+ 'post_title' => 'Page Template',
53
+ 'post_content' => $this->get_template_content( $header_id, $footer_id ),
54
+ 'post_status' => 'publish',
55
+ 'post_type' => 'wp_template',
56
+ 'comment_status' => 'closed',
57
+ 'ping_status' => 'closed',
58
+ ]
59
+ );
60
+
61
+ if ( ! term_exists( 'footer', 'wp_template_part_type' ) ) {
62
+ wp_insert_term( 'footer', 'wp_template_part_type' );
63
+ }
64
+
65
+ wp_set_object_terms( $page_template_id, 'page_template', 'wp_template_type' );
66
+ }
67
+
68
+ /**
69
+ * Returns default header template part content.
70
+ *
71
+ * @return string
72
+ */
73
+ public function get_header_content() {
74
+ // TODO: replace with header blocks once they are ready.
75
+ return '<!-- wp:heading -->' .
76
+ '<h2>Test Header Content</h2>' .
77
+ '<!-- /wp:heading -->';
78
+ }
79
+
80
+ /**
81
+ * Returns default footer template part content.
82
+ *
83
+ * @return string
84
+ */
85
+ public function get_footer_content() {
86
+ // TODO: replace with footer blocks once they are ready.
87
+ return '<!-- wp:heading -->' .
88
+ '<h2>Test Footer Content</h2>' .
89
+ '<!-- /wp:heading -->';
90
+ }
91
+
92
+ /**
93
+ * Returns default page template content.
94
+ *
95
+ * @param int $header_id ID of referenced header template part CPT.
96
+ * @param int $footer_id ID of referenced footer template part CPT.
97
+ *
98
+ * @return string
99
+ */
100
+ public function get_template_content( $header_id, $footer_id ) {
101
+ return "<!-- wp:a8c/template {\"templateId\":$header_id,\"align\":\"full\"} /-->" .
102
+ '<!-- wp:a8c/post-content {"align":"full"} /-->' .
103
+ "<!-- wp:a8c/template {\"templateId\":$footer_id,\"align\":\"full\"} /-->";
104
+ }
105
+ }
full-site-editing/utils/class-a8c-wp-template.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A8C WP Template file.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Class A8C_WP_Template
10
+ */
11
+ class A8C_WP_Template {
12
+ const TEMPLATE_META_KEY = '_wp_template_id';
13
+
14
+ /**
15
+ * ID of the current post that's being rendered.
16
+ *
17
+ * @var int $current_post_id ID of the current post.
18
+ */
19
+ private $current_post_id;
20
+
21
+ /**
22
+ * ID of the template associated with the current post.
23
+ *
24
+ * @var int $template_id ID of the template associated with the current post.
25
+ */
26
+ private $template_id;
27
+
28
+
29
+ /**
30
+ * A8C_WP_Template constructor.
31
+ *
32
+ * @param int|null $post_id Defaults to current post id if not passed.
33
+ */
34
+ public function __construct( $post_id = null ) {
35
+ if ( null === $post_id ) {
36
+ $post_id = get_post()->ID;
37
+ }
38
+
39
+ $this->current_post_id = $post_id;
40
+ $this->template_id = $this->get_template_id();
41
+ }
42
+
43
+ /**
44
+ * Returns template ID for current page if it exists.
45
+ *
46
+ * If template id is set in current post's meta (_wp_template_id) it will be returned.
47
+ * Otherwise it falls back to global page template that is marked with page_template term
48
+ * in wp_template_type taxonomy. Note that having only one term of this kind is not
49
+ * currently enforced, so we'll just pick the latest page template that was created
50
+ * (based on its post ID).
51
+ *
52
+ * @return null|int template ID for current page, or null if it doesn't exist.
53
+ */
54
+ public function get_template_id() {
55
+ // If the specific template is referenced in post meta, use it.
56
+ $template_id = get_post_meta( $this->current_post_id, self::TEMPLATE_META_KEY, true );
57
+
58
+ if ( ! empty( $template_id ) ) {
59
+ return $template_id;
60
+ }
61
+
62
+ // Otherwise, fall back to latest global page template.
63
+ $term = get_term_by( 'name', 'page_template', 'wp_template_type', ARRAY_A );
64
+
65
+ if ( ! isset( $term['term_id'] ) ) {
66
+ return null;
67
+ }
68
+
69
+ $template_ids = get_objects_in_term( $term['term_id'], $term['taxonomy'], [ 'order' => 'DESC' ] );
70
+
71
+ if ( empty( $template_ids ) ) {
72
+ return null;
73
+ }
74
+
75
+ return $template_ids[0];
76
+ }
77
+
78
+ /**
79
+ * Returns template's post content.
80
+ *
81
+ * @return null|string
82
+ */
83
+ public function get_template_content() {
84
+ if ( empty( $this->template_id ) ) {
85
+ return null;
86
+ }
87
+
88
+ $template_post = get_post( $this->template_id );
89
+
90
+ return null === $template_post ? null : $template_post->post_content;
91
+ }
92
+
93
+ /**
94
+ * Returns array of blocks that represent the template.
95
+ *
96
+ * @return array
97
+ */
98
+ public function get_template_blocks() {
99
+ $template_content = $this->get_template_content();
100
+
101
+ $template_blocks = parse_blocks( $template_content );
102
+
103
+ return is_array( $template_blocks ) ? $template_blocks : [];
104
+ }
105
+
106
+ /**
107
+ * Returns the post ID of the template part CPT that represents the Header in this template.
108
+ *
109
+ * This is simplified for now and we are just assuming that the first template part in every
110
+ * template will represent the Header.
111
+ *
112
+ * @return null|int Header template part ID if it exists or null otherwise.
113
+ */
114
+ public function get_header_id() {
115
+ $template_blocks = $this->get_template_blocks();
116
+
117
+ if ( empty( $template_blocks ) ) {
118
+ return null;
119
+ }
120
+
121
+ // TODO: Incorporate wp_template_part taxonomy checks.
122
+ if ( ! isset( $template_blocks[0]['attrs']['templateId'] ) ) {
123
+ return null;
124
+ }
125
+
126
+ $header_id = $template_blocks[0]['attrs']['templateId'];
127
+
128
+ if ( ! has_term( 'header', 'wp_template_part_type', $header_id ) ) {
129
+ return null;
130
+ }
131
+
132
+ return $header_id;
133
+ }
134
+
135
+ /**
136
+ * Returns the post ID of the template part CPT that represents the Footer in this template.
137
+ *
138
+ * This is simplified for now and we are just assuming that the last template part in every
139
+ * template will represent the Footer.
140
+ *
141
+ * @return null|int Footer template part ID if it exists or null otherwise.
142
+ */
143
+ public function get_footer_id() {
144
+ $template_blocks = $this->get_template_blocks();
145
+
146
+ if ( ! isset( end( $template_blocks )['attrs']['templateId'] ) ) {
147
+ return null;
148
+ }
149
+
150
+ $footer_id = end( $template_blocks )['attrs']['templateId'];
151
+
152
+ if ( ! has_term( 'footer', 'wp_template_part_type', $footer_id ) ) {
153
+ return null;
154
+ }
155
+
156
+ return $footer_id;
157
+ }
158
+
159
+ /**
160
+ * Returns header template part content of current template.
161
+ *
162
+ * @return null|string
163
+ */
164
+ public function get_header_content() {
165
+ $header_id = $this->get_header_id();
166
+
167
+ if ( null === $header_id ) {
168
+ return null;
169
+ }
170
+
171
+ $header = get_post( $header_id );
172
+
173
+ if ( null === $header ) {
174
+ return null;
175
+ }
176
+
177
+ return $header->post_content;
178
+ }
179
+
180
+ /**
181
+ * Returns footer template part content of current template.
182
+ *
183
+ * @return null|string
184
+ */
185
+ public function get_footer_content() {
186
+ $footer_id = $this->get_footer_id();
187
+
188
+ if ( null === $footer_id ) {
189
+ return null;
190
+ }
191
+
192
+ $footer = get_post( $footer_id );
193
+
194
+ if ( null === $footer ) {
195
+ return null;
196
+ }
197
+
198
+ return $footer->post_content;
199
+ }
200
+ }
full-site-editing/utils/replace-template-parts.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Replace template parts file.
4
+ *
5
+ * @package full-site-editing
6
+ */
7
+
8
+ /**
9
+ * Callback function that will be executed before the output buffer is flushed.
10
+ *
11
+ * It is processing the final HTML before it's sent to the user and replacing different
12
+ * page areas with appropriate template parts (wp_template_part CPT) depending on the
13
+ * template (wp_template CPT) that has been assigned to the current page.
14
+ *
15
+ * @param string $html HTML code passed by output buffer.
16
+ *
17
+ * @return string HTML code with replaced header node if it exists.
18
+ */
19
+ function a8c_fse_replace_template_parts( $html ) {
20
+ $page_template = new A8C_WP_Template();
21
+
22
+ // Array that defines replacement pairs. 'xpath_query' specifies the element from the original HTML
23
+ // that should be replaced, and 'fse_content' contains the replacement HTML code.
24
+ $replacements = [
25
+ 'header' => [
26
+ // Query the first <header> element that contains the 'site-header' class.
27
+ // Note that this is not always the direct descendant of <body> since it's sometimes wrapped in a <div>.
28
+ 'xpath_query' => "(/html/body//header[@class='site-header'])[1]",
29
+ 'fse_content' => $page_template->get_header_content(),
30
+ ],
31
+ 'footer' => [
32
+ // Query the first <footer> element that contains the 'site-footer' class.
33
+ 'xpath_query' => "(/html/body//footer[@class='site-footer'])[1]",
34
+ 'fse_content' => $page_template->get_footer_content(),
35
+ ],
36
+ ];
37
+
38
+ $doc = new DOMDocument();
39
+ // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
40
+ $doc->preserveWhiteSpace = false;
41
+ // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
42
+ @$doc->loadHTML( mb_convert_encoding( $html, 'HTML-ENTITIES', 'UTF-8' ) );
43
+
44
+ $temp_doc = new DOMDocument();
45
+ $temp_doc->preserveWhiteSpace = false;
46
+
47
+ foreach ( $replacements as $replacement ) {
48
+ if ( empty( $replacement['xpath_query'] ) || empty( $replacement['fse_content'] ) ) {
49
+ continue;
50
+ }
51
+
52
+ $xpath = new DOMXPath( $doc );
53
+ $candidate_nodes = $xpath->query( $replacement['xpath_query'] );
54
+
55
+ if ( 0 === $candidate_nodes->length ) {
56
+ continue;
57
+ }
58
+
59
+ $node_to_replace = $candidate_nodes[0];
60
+
61
+ @$temp_doc->loadHTML( mb_convert_encoding( $replacement['fse_content'], 'HTML-ENTITIES', 'UTF-8' ) );
62
+
63
+ $fse_node = $doc->importNode( $temp_doc->documentElement, true );
64
+ $node_to_replace->parentNode->replaceChild( $fse_node, $node_to_replace );
65
+ }
66
+
67
+ return $doc->saveHTML();
68
+ }
lib/feature-flags/class-a8c-full-site-editing-feature-flags.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // phpcs:ignoreFile
3
+ // This file is not currently used
4
+ /**
5
+ * Feature flags file.
6
+ *
7
+ * @package full-site-editing
8
+ */
9
+
10
+ /**
11
+ * Class A8C_Full_Site_Editing_Feature_Flags
12
+ */
13
+ class A8C_Full_Site_Editing_Feature_Flags {
14
+ /**
15
+ * Class instance.
16
+ *
17
+ * @var A8C_Full_Site_Editing_Feature_Flags
18
+ */
19
+ private static $instance = null;
20
+
21
+ /**
22
+ * Feature flags.
23
+ *
24
+ * @var array
25
+ */
26
+ private $flags = [];
27
+
28
+ /**
29
+ * Parameter and cookie name for storing/retrieving the feature flags.
30
+ *
31
+ * @var string
32
+ */
33
+ const FEATURE_FLAGS = 'fse_feature_flags';
34
+
35
+ /**
36
+ * A8C_Full_Site_Editing_Feature_Flags constructor.
37
+ */
38
+ private function __construct() {
39
+ $this->set_flags();
40
+ }
41
+
42
+ /**
43
+ * Creates instance.
44
+ *
45
+ * @return A8C_Full_Site_Editing_Feature_Flags
46
+ */
47
+ public static function get_instance() {
48
+ if ( is_null( self::$instance ) ) {
49
+ self::$instance = new self();
50
+ }
51
+
52
+ return self::$instance;
53
+ }
54
+
55
+ /**
56
+ * Get the feature flags.
57
+ *
58
+ * @return array
59
+ */
60
+ public function get_flags() {
61
+ return $this->flags;
62
+ }
63
+
64
+ /**
65
+ * Check if a feature flag is enabled.
66
+ *
67
+ * @param string $flag_name Feature flag.
68
+ * @return boolean
69
+ */
70
+ public function is_enabled( $flag_name ) {
71
+ if ( ! isset( $flag_name, $this->flags[ $flag_name ] ) ) {
72
+ return false;
73
+ }
74
+
75
+ return (bool) $this->flags[ $flag_name ];
76
+ }
77
+
78
+ /**
79
+ * Set the feature flags based on GET parameter or cookie value.
80
+ */
81
+ private function set_flags() {
82
+ $flags = null;
83
+
84
+ $has_flags_param = isset( $_GET[ self::FEATURE_FLAGS ] );
85
+ $has_flags_cookie = isset( $_COOKIE[ self::FEATURE_FLAGS ] );
86
+
87
+ // Remove all of the flag values when empty parameter is passed.
88
+ if ( $has_flags_param && empty( $_GET[ self::FEATURE_FLAGS ] ) ) {
89
+ setcookie( self::FEATURE_FLAGS, '', time() - 3600 );
90
+ $this->flags = [];
91
+ return;
92
+ }
93
+
94
+ if ( $has_flags_param ) {
95
+ setcookie( self::FEATURE_FLAGS, $_GET[ self::FEATURE_FLAGS ] );
96
+ $flags = $_GET[ self::FEATURE_FLAGS ];
97
+ } elseif ( $has_flags_cookie ) {
98
+ $flags = $_COOKIE[ self::FEATURE_FLAGS ];
99
+ }
100
+
101
+ if ( empty( $flags ) ) {
102
+ $this->flags = [];
103
+ return;
104
+ }
105
+
106
+ // Feature flags are represented as a string of comma-separated feature flag names.
107
+ // For example: "flag1,flag2,-flag3" (leading "-" denotes that the given flag is disabled).
108
+ foreach ( explode( ',', $flags ) as $flag ) {
109
+ $flag = trim( $flag );
110
+ $is_enabled = '-' !== $flag[0];
111
+
112
+ // Strip "-" for disabled flags to obtain the correct name
113
+ $name = $is_enabled ? $flag : substr( $flag, 1 );
114
+
115
+ $this->flags[ $name ] = $is_enabled;
116
+ }
117
+ }
118
+ }
readme.txt CHANGED
@@ -1,5 +1,5 @@
1
  === Full Site Editing ===
2
- 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
@@ -40,6 +40,9 @@ This plugin is experimental, so we don't provide any support for it outside of w
40
 
41
  == Changelog ==
42
 
 
 
 
43
  = 0.1.1 =
44
  * Latest round of updates
45
 
1
  === Full Site Editing ===
2
+ Contributors: alexislloyd, allancole, automattic, codebykat, copons, dmsnell, get_dave, glendaviesnz, gwwar, iamtakashi, Joen, kwight, marekhrabe, mattwiebe, mmtr86, mppfeiffer, nrqsnchz, obenland, okenobi, vindl
3
  Tags: block, blocks, editor, gutenberg, page
4
  Requires at least: 5.0
5
  Tested up to: 5.2
40
 
41
  == Changelog ==
42
 
43
+ = 0.2 =
44
+ * Bug fixes and performance improvements.
45
+
46
  = 0.1.1 =
47
  * Latest round of updates
48
 
starter-page-templates/class-starter-page-templates.php CHANGED
@@ -21,8 +21,9 @@ class Starter_Page_Templates {
21
  * Starter_Page_Templates constructor.
22
  */
23
  private function __construct() {
24
- add_action( 'init', array( $this, 'register_scripts' ) );
25
- add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_assets' ) );
 
26
  }
27
 
28
  /**
@@ -45,12 +46,52 @@ class Starter_Page_Templates {
45
  wp_register_script(
46
  'starter-page-templates',
47
  plugins_url( 'dist/starter-page-templates.js', __FILE__ ),
48
- array( 'wp-plugins', 'wp-edit-post', 'wp-element' ),
49
  filemtime( plugin_dir_path( __FILE__ ) . 'dist/starter-page-templates.js' ),
50
  true
51
  );
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  /**
55
  * Enqueue block editor assets.
56
  */
@@ -65,34 +106,46 @@ class Starter_Page_Templates {
65
  // Load templates for this site.
66
  $vertical_data = $this->fetch_vertical_data();
67
  if ( empty( $vertical_data ) ) {
 
68
  return;
69
  }
70
- $vertical_name = $vertical_data['vertical'];
 
71
  $vertical_templates = $vertical_data['templates'];
72
 
73
  // Bail early if we have no templates to offer.
74
- if ( empty( $vertical_templates ) ) {
 
75
  return;
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' ),
83
- 'vertical' => $vertical_name,
84
- );
85
- $default_templates = array(
86
- array(
87
  'title' => 'Blank',
88
  'slug' => 'blank',
89
- ),
90
-
91
- );
92
- $site_info = get_option( 'site_contact_info', array() );
93
- $config = array(
94
- 'siteInformation' => array_merge( $default_info, $site_info ),
95
- 'templates' => array_merge( $default_templates, $vertical_templates ),
 
 
 
 
 
 
 
 
 
96
  );
97
  wp_localize_script( 'starter-page-templates', 'starterPageTemplatesConfig', $config );
98
 
@@ -104,7 +157,7 @@ class Starter_Page_Templates {
104
  wp_enqueue_style(
105
  'starter-page-templates',
106
  plugins_url( 'dist/' . $style_file, __FILE__ ),
107
- array(),
108
  filemtime( plugin_dir_path( __FILE__ ) . 'dist/' . $style_file )
109
  );
110
  }
@@ -116,15 +169,20 @@ class Starter_Page_Templates {
116
  */
117
  public function fetch_vertical_data() {
118
  $vertical_id = get_option( 'site_vertical', 'default' );
119
- $transient_key = 'starter_page_templates_' . $vertical_id;
120
  $vertical_templates = get_transient( $transient_key );
121
 
122
  // Load fresh data if we don't have any or vertical_id doesn't match.
123
- if ( false === $vertical_templates ) {
124
- $request_url = 'https://public-api.wordpress.com/wpcom/v2/verticals/' . $vertical_id . '/templates';
 
 
 
 
 
125
  $response = wp_remote_get( esc_url_raw( $request_url ) );
126
  if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
127
- return array();
128
  }
129
  $vertical_templates = json_decode( wp_remote_retrieve_body( $response ), true );
130
  set_transient( $transient_key, $vertical_templates, DAY_IN_SECONDS );
@@ -132,4 +190,21 @@ class Starter_Page_Templates {
132
 
133
  return $vertical_templates;
134
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }
21
  * Starter_Page_Templates constructor.
22
  */
23
  private function __construct() {
24
+ add_action( 'init', [ $this, 'register_scripts' ] );
25
+ add_action( 'init', [ $this, 'register_meta_field' ] );
26
+ add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_assets' ] );
27
  }
28
 
29
  /**
46
  wp_register_script(
47
  'starter-page-templates',
48
  plugins_url( 'dist/starter-page-templates.js', __FILE__ ),
49
+ [ 'wp-plugins', 'wp-edit-post', 'wp-element' ],
50
  filemtime( plugin_dir_path( __FILE__ ) . 'dist/starter-page-templates.js' ),
51
  true
52
  );
53
  }
54
 
55
+ /**
56
+ * Register meta field for storing the template identifier.
57
+ */
58
+ public function register_meta_field() {
59
+ $args = [
60
+ 'type' => 'string',
61
+ 'description' => 'Selected template',
62
+ 'single' => true,
63
+ 'show_in_rest' => true,
64
+ 'object_subtype' => 'page',
65
+ 'auth_callback' => function() {
66
+ return current_user_can( 'edit_posts' );
67
+ },
68
+ ];
69
+ register_meta( 'post', '_starter_page_template', $args );
70
+ }
71
+
72
+ /**
73
+ * Pass error message to frontend JavaScript console.
74
+ *
75
+ * @param string $message Error message.
76
+ */
77
+ public function pass_error_to_frontend( $message ) {
78
+ wp_register_script(
79
+ 'starter-page-templates-error',
80
+ null,
81
+ [],
82
+ '1.O',
83
+ true
84
+ );
85
+ wp_add_inline_script(
86
+ 'starter-page-templates-error',
87
+ sprintf(
88
+ 'console.warn(%s);',
89
+ wp_json_encode( $message )
90
+ )
91
+ );
92
+ wp_enqueue_script( 'starter-page-templates-error' );
93
+ }
94
+
95
  /**
96
  * Enqueue block editor assets.
97
  */
106
  // Load templates for this site.
107
  $vertical_data = $this->fetch_vertical_data();
108
  if ( empty( $vertical_data ) ) {
109
+ $this->pass_error_to_frontend( __( 'No data received from the vertical API. Skipped showing modal window with template selection.', 'full-site-editing' ) );
110
  return;
111
  }
112
+ $vertical = $vertical_data['vertical'];
113
+ $segment = $vertical_data['segment'];
114
  $vertical_templates = $vertical_data['templates'];
115
 
116
  // Bail early if we have no templates to offer.
117
+ if ( empty( $vertical_templates ) || empty( $vertical ) || empty( $segment ) ) {
118
+ $this->pass_error_to_frontend( __( 'No templates available. Skipped showing modal window with template selection.', 'full-site-editing' ) );
119
  return;
120
  }
121
 
122
  wp_enqueue_script( 'starter-page-templates' );
123
  wp_set_script_translations( 'starter-page-templates', 'full-site-editing' );
124
 
125
+ $default_info = [
126
  'title' => get_bloginfo( 'name' ),
127
+ 'vertical' => $vertical['name'],
128
+ ];
129
+ $default_templates = [
130
+ [
131
  'title' => 'Blank',
132
  'slug' => 'blank',
133
+ ],
134
+ ];
135
+ $site_info = get_option( 'site_contact_info', [] );
136
+ /**
137
+ * Filters the config before it's passed to the frontend.
138
+ *
139
+ * @param array $config The config.
140
+ */
141
+ $config = apply_filters(
142
+ 'fse_starter_page_templates_config',
143
+ [
144
+ 'siteInformation' => array_merge( $default_info, $site_info ),
145
+ 'templates' => array_merge( $default_templates, $vertical_templates ),
146
+ 'vertical' => $vertical,
147
+ 'segment' => $segment,
148
+ ]
149
  );
150
  wp_localize_script( 'starter-page-templates', 'starterPageTemplatesConfig', $config );
151
 
157
  wp_enqueue_style(
158
  'starter-page-templates',
159
  plugins_url( 'dist/' . $style_file, __FILE__ ),
160
+ [],
161
  filemtime( plugin_dir_path( __FILE__ ) . 'dist/' . $style_file )
162
  );
163
  }
169
  */
170
  public function fetch_vertical_data() {
171
  $vertical_id = get_option( 'site_vertical', 'default' );
172
+ $transient_key = implode( '_', [ 'starter_page_templates', 'v2', $vertical_id, get_locale() ] );
173
  $vertical_templates = get_transient( $transient_key );
174
 
175
  // Load fresh data if we don't have any or vertical_id doesn't match.
176
+ if ( false === $vertical_templates || ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
177
+ $request_url = add_query_arg(
178
+ [
179
+ '_locale' => $this->get_iso_639_locale(),
180
+ ],
181
+ 'https://public-api.wordpress.com/wpcom/v2/verticals/' . $vertical_id . '/templates'
182
+ );
183
  $response = wp_remote_get( esc_url_raw( $request_url ) );
184
  if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
185
+ return [];
186
  }
187
  $vertical_templates = json_decode( wp_remote_retrieve_body( $response ), true );
188
  set_transient( $transient_key, $vertical_templates, DAY_IN_SECONDS );
190
 
191
  return $vertical_templates;
192
  }
193
+
194
+ /**
195
+ * Returns ISO 639 conforming locale string.
196
+ *
197
+ * @return string ISO 639 locale string
198
+ */
199
+ private function get_iso_639_locale() {
200
+ $language = strtolower( get_locale() );
201
+
202
+ if ( in_array( $language, [ 'zh_tw', 'zh_cn' ], true ) ) {
203
+ $language = str_replace( '_', '-', $language );
204
+ } else {
205
+ $language = preg_replace( '/(_.*)$/i', '', $language );
206
+ }
207
+
208
+ return $language;
209
+ }
210
  }
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){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}}
1
+ .page-template-modal-screen-overlay{background-color:rgba(0,0,0,.7);animation:none}@media screen and (min-width:783px){body:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{left:36px}}@media screen and (min-width:961px){body:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{left:160px}}body.admin-bar:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{top:46px}@media screen and (min-width:783px){body.admin-bar:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{top:32px}}.page-template-modal{width:100%;height:100vh;max-width:800px;animation:none}.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;margin-left:auto;margin-right:auto}.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;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.page-template-modal__list .template-selector-control__label:hover{background:#f3f4f5}.page-template-modal__list .template-selector-control__label:focus{background:#f3f4f5;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:133.33%;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-blocks","wp-components","wp-compose","wp-data","wp-element","wp-i18n","wp-plugins"]
1
+ ["lodash","wp-blocks","wp-components","wp-compose","wp-data","wp-element","wp-i18n","wp-nux","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=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,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 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)}})}]));
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=22)}([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=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=function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}},function(e,t){e.exports=wp.compose},function(e,t){e.exports=wp.components},function(e,t,n){var o=n(3);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){e.exports=wp.data},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t){function n(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}e.exports=function(e,t,o){return t&&n(e.prototype,t),o&&n(e,o),e}},function(e,t,n){var o=n(17),r=n(4);e.exports=function(e,t){return!t||"object"!==o(t)&&"function"!=typeof t?r(e):t}},function(e,t){function n(t){return e.exports=n=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},n(t)}e.exports=n},function(e,t,n){var o=n(18);e.exports=function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&o(e,t)}},function(e,t){e.exports=wp.plugins},function(e,t){e.exports=wp.blocks},function(e,t,n){var o;
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 r(){for(var e=[],t=0;t<arguments.length;t++){var o=arguments[t];if(o){var i=typeof o;if("string"===i||"number"===i)e.push(o);else if(Array.isArray(o)&&o.length){var l=r.apply(null,o);l&&e.push(l)}else if("object"===i)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){function n(e){return(n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(t){return"function"==typeof Symbol&&"symbol"===n(Symbol.iterator)?e.exports=o=function(e){return n(e)}:e.exports=o=function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":n(e)},o(t)}e.exports=o},function(e,t){function n(t,o){return e.exports=n=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},n(t,o)}e.exports=n},function(e,t){e.exports=wp.nux},function(e,t,n){},,function(e,t,n){"use strict";n.r(t);var o=n(7),r=n.n(o),i=n(9),l=n.n(i),a=n(10),c=n.n(a),s=n(11),u=n.n(s),p=n(12),f=n.n(p),m=n(4),d=n.n(m),b=n(13),_=n.n(b),y=n(3),v=n.n(y),g=n(0),O=n(2),j=n(1),h=n(5),w=n(6),x=n(14),E=n(8),P=n(15),S=(n(19),{Address:Object(j._x)("123 Main St","default address","full-site-editing"),Phone:Object(j._x)("555-555-5555","default phone number","full-site-editing"),CompanyName:Object(j._x)("Your Company Name","default company name","full-site-editing"),Vertical:Object(j._x)("Business","default vertical name","full-site-editing")}),k={CompanyName:"title",Address:"address",Phone:"phone",Vertical:"vertical"},N=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.replace(/{{(\w+)}}/g,function(e,n){var o=S[n];return t[k[n]]||o||n})},T=(n(20),n(16)),C=n.n(T);var M=Object(h.withInstanceId)(function(e){var t=e.label,n=e.className,o=e.help,r=e.instanceId,i=e.onClick,l=e.templates,a=void 0===l?[]:l,c="template-selector-control-".concat(r),s=function(e){return i(e.target.value)};return Object(O.isEmpty)(a)?null:Object(g.createElement)(w.BaseControl,{label:t,id:c,help:o,className:C()(n,"template-selector-control")},Object(g.createElement)("ul",{className:"template-selector-control__options"},a.map(function(e,t){return Object(g.createElement)("li",{key:"".concat(c,"-").concat(t),className:"template-selector-control__option"},Object(g.createElement)("button",{type:"button",id:"".concat(c,"-").concat(t),className:"template-selector-control__label",value:e.value,onClick:s,"aria-describedby":o?"".concat(c,"__help"):void 0},Object(g.createElement)("div",{className:"template-selector-control__media-wrap"},e.preview&&Object(g.createElement)("img",{className:"template-selector-control__media",src:e.preview,alt:e.previewAlt||""})),e.label))})))});window._tkq=window._tkq||[];var q,A=null,I=function(e,t){A&&window._tkq.push(["recordEvent","a8c_full_site_editing_template_selector_dismiss",{blog_id:A.blogid,segment_id:e,vertical_id:t}])},B=function(e,t,n){A&&window._tkq.push(["recordEvent","a8c_full_site_editing_template_selector_template_selected",{blog_id:A.blogid,segment_id:e,vertical_id:t,template:n}])},D=function(e){function t(e){var n;return l()(this,t),n=u()(this,f()(t).call(this)),v()(d()(n),"state",{isLoading:!1}),v()(d()(n),"selectTemplate",function(e){n.setState({isOpen:!1}),B(n.props.segment.id,n.props.vertical.id,e);var t=n.props.templates[e];if(n.props.saveTemplateChoice(t),Object(O.has)(t,"content")){var o=r()({},t,{title:N(t.title,n.props.siteInformation),content:N(t.content,n.props.siteInformation)});n.props.insertTemplate(o)}}),v()(d()(n),"closeModal",function(){n.setState({isOpen:!1}),I(n.props.segment.id,n.props.vertical.id)}),n.state.isOpen=!Object(O.isEmpty)(e.templates),n}return _()(t,e),c()(t,[{key:"componentDidMount",value:function(){var e,t;this.state.isOpen&&(e=this.props.segment.id,t=this.props.vertical.id,A&&window._tkq.push(["recordEvent","a8c_full_site_editing_template_selector_view",{blog_id:A.blogid,segment_id:e,vertical_id:t}]))}},{key:"render",value:function(){var e=this;return this.state.isOpen?Object(g.createElement)(w.Modal,{title:Object(j.__)("Select Page Template","full-site-editing"),onRequestClose:this.closeModal,className:"page-template-modal",overlayClassName:"page-template-modal-screen-overlay"},Object(g.createElement)("div",{className:"page-template-modal__inner"},Object(g.createElement)("form",{className:"page-template-modal__form"},Object(g.createElement)("fieldset",{className:"page-template-modal__list"},Object(g.createElement)("legend",{className:"page-template-modal__intro"},Object(g.createElement)("p",null,Object(j.__)("Pick a Template that matches the purpose of your page.","full-site-editing")),Object(g.createElement)("p",null,Object(j.__)("You can customize each Template to meet your needs.","full-site-editing"))),Object(g.createElement)(M,{label:Object(j.__)("Template","full-site-editing"),templates:Object(O.map)(this.props.templates,function(e){return{label:e.title,value:e.slug,preview:e.preview,previewAlt:e.description}}),onClick:function(t){return e.selectTemplate(t)}}))))):null}}]),t}(g.Component),R=Object(h.compose)(Object(E.withSelect)(function(e){return{getMeta:function(){return e("core/editor").getEditedPostAttribute("meta")}}}),Object(E.withDispatch)(function(e,t){e("core/nux").disableTips();var n=e("core/editor");return{saveTemplateChoice:function(e){var o=t.getMeta();n.editPost({meta:r()({},o,{_starter_page_template:e.slug})})},insertTemplate:function(e){n.editPost({title:e.title});var t=Object(P.parse)(e.content);n.insertBlocks(t)}}}))(D),U=window.starterPageTemplatesConfig,V=U.siteInformation,Y=void 0===V?{}:V,z=U.templates,L=void 0===z?[]:z,F=U.vertical,G=U.segment,H=U.tracksUserData;H&&(A=q=H,window._tkq.push(["identifyUser",q.userid,q.username])),Object(x.registerPlugin)("page-templates",{render:function(){return Object(g.createElement)(R,{templates:Object(O.keyBy)(L,"slug"),vertical:F,segment:G,siteInformation:Y})}})}]));
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){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}}
1
+ .page-template-modal-screen-overlay{background-color:rgba(0,0,0,.7);animation:none}@media screen and (min-width:783px){body:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{right:36px}}@media screen and (min-width:961px){body:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{right:160px}}body.admin-bar:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{top:46px}@media screen and (min-width:783px){body.admin-bar:not(.is-fullscreen-mode) .page-template-modal-screen-overlay{top:32px}}.page-template-modal{width:100%;height:100vh;max-width:800px;animation:none}.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;margin-right:auto;margin-left:auto}.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;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.page-template-modal__list .template-selector-control__label:hover{background:#f3f4f5}.page-template-modal__list .template-selector-control__label:focus{background:#f3f4f5;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:133.33%;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
@@ -18,7 +18,7 @@ function TemplateSelectorControl( {
18
  onClick,
19
  templates = [],
20
  } ) {
21
- const id = `inspector-radio-control-${ instanceId }`;
22
  const handleButtonClick = event => onClick( event.target.value );
23
 
24
  if ( isEmpty( templates ) ) {
18
  onClick,
19
  templates = [],
20
  } ) {
21
+ const id = `template-selector-control-${ instanceId }`;
22
  const handleButtonClick = event => onClick( event.target.value );
23
 
24
  if ( isEmpty( templates ) ) {
starter-page-templates/page-template-modal/index.js CHANGED
@@ -1,13 +1,15 @@
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
@@ -15,63 +17,61 @@ import { parse as parseBlocks } from '@wordpress/blocks';
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,
39
- template => {
40
- template.preview = PREVIEWS_BY_SLUG[ template.slug ];
41
- return template;
42
- }
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">
@@ -92,27 +92,78 @@ const PageTemplateModal = withState( {
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
  } );
1
  /**
2
  * External dependencies
3
  */
4
+ import { has, isEmpty, keyBy, map } from 'lodash';
5
  import { __ } from '@wordpress/i18n';
6
+ import { compose } from '@wordpress/compose';
7
  import { Modal } from '@wordpress/components';
8
  import { registerPlugin } from '@wordpress/plugins';
9
+ import { withDispatch, withSelect } from '@wordpress/data';
10
  import { parse as parseBlocks } from '@wordpress/blocks';
11
+ import { Component } from '@wordpress/element';
12
+ import '@wordpress/nux';
13
 
14
  /**
15
  * Internal dependencies
17
  import replacePlaceholders from './utils/replace-placeholders';
18
  import './styles/starter-page-templates-editor.scss';
19
  import TemplateSelectorControl from './components/template-selector-control';
20
+ import { trackDismiss, trackSelection, trackView, initializeWithIdentity } from './utils/tracking';
21
 
22
+ class PageTemplateModal extends Component {
23
+ state = {
24
+ isLoading: false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  };
 
 
 
 
 
 
 
 
26
 
27
+ constructor( props ) {
28
+ super();
29
+ this.state.isOpen = ! isEmpty( props.templates );
30
+ }
31
 
32
+ componentDidMount() {
33
+ if ( this.state.isOpen ) {
34
+ trackView( this.props.segment.id, this.props.vertical.id );
35
+ }
36
  }
37
 
38
+ selectTemplate = newTemplate => {
39
+ this.setState( { isOpen: false } );
40
+ trackSelection( this.props.segment.id, this.props.vertical.id, newTemplate );
41
+
42
+ const template = this.props.templates[ newTemplate ];
43
+ this.props.saveTemplateChoice( template );
44
+
45
+ // Skip inserting if there's nothing to insert.
46
+ if ( ! has( template, 'content' ) ) {
47
+ return;
48
+ }
49
+
50
+ const processedTemplate = {
51
+ ...template,
52
+ title: replacePlaceholders( template.title, this.props.siteInformation ),
53
+ content: replacePlaceholders( template.content, this.props.siteInformation ),
54
+ };
55
+
56
+ this.props.insertTemplate( processedTemplate );
57
+ };
58
+
59
+ closeModal = () => {
60
+ this.setState( { isOpen: false } );
61
+ trackDismiss( this.props.segment.id, this.props.vertical.id );
62
+ };
63
+
64
+ render() {
65
+ if ( ! this.state.isOpen ) {
66
+ return null;
67
+ }
68
+
69
+ return (
70
  <Modal
71
  title={ __( 'Select Page Template', 'full-site-editing' ) }
72
+ onRequestClose={ this.closeModal }
73
  className="page-template-modal"
74
+ overlayClassName="page-template-modal-screen-overlay"
75
  >
76
  <div className="page-template-modal__inner">
77
  <form className="page-template-modal__form">
92
  </legend>
93
  <TemplateSelectorControl
94
  label={ __( 'Template', 'full-site-editing' ) }
95
+ templates={ map( this.props.templates, template => ( {
96
  label: template.title,
97
  value: template.slug,
98
+ preview: template.preview,
99
+ previewAlt: template.description,
100
  } ) ) }
101
+ onClick={ newTemplate => this.selectTemplate( newTemplate ) }
 
 
 
102
  />
103
  </fieldset>
104
  </form>
105
  </div>
106
  </Modal>
107
+ );
108
+ }
109
+ }
110
+
111
+ const PageTemplatesPlugin = compose(
112
+ withSelect( select => ( {
113
+ getMeta: () => select( 'core/editor' ).getEditedPostAttribute( 'meta' ),
114
+ } ) ),
115
+ withDispatch( ( dispatch, ownProps ) => {
116
+ // Disable tips right away as the collide with the modal window.
117
+ dispatch( 'core/nux' ).disableTips();
118
+
119
+ const editorDispatcher = dispatch( 'core/editor' );
120
+ return {
121
+ saveTemplateChoice: template => {
122
+ // Save selected template slug in meta.
123
+ const currentMeta = ownProps.getMeta();
124
+ editorDispatcher.editPost( {
125
+ meta: {
126
+ ...currentMeta,
127
+ _starter_page_template: template.slug,
128
+ },
129
+ } );
130
+ },
131
+ insertTemplate: template => {
132
+ // Set post title.
133
+ editorDispatcher.editPost( {
134
+ title: template.title,
135
+ } );
136
+
137
+ // Insert blocks.
138
+ const blocks = parseBlocks( template.content );
139
+ editorDispatcher.insertBlocks( blocks );
140
+ },
141
+ };
142
+ } )
143
+ )( PageTemplateModal );
144
+
145
+ // Load config passed from backend.
146
+ const {
147
+ siteInformation = {},
148
+ templates = [],
149
+ vertical,
150
+ segment,
151
+ tracksUserData,
152
+ } = window.starterPageTemplatesConfig;
153
+
154
+ if ( tracksUserData ) {
155
+ initializeWithIdentity( tracksUserData );
156
+ }
157
 
158
  registerPlugin( 'page-templates', {
159
  render: function() {
160
+ return (
161
+ <PageTemplatesPlugin
162
+ templates={ keyBy( templates, 'slug' ) }
163
+ vertical={ vertical }
164
+ segment={ segment }
165
+ siteInformation={ siteInformation }
166
+ />
167
+ );
168
  },
169
  } );
starter-page-templates/page-template-modal/styles/starter-page-templates-editor.scss CHANGED
@@ -11,25 +11,40 @@
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;
26
- transform: translateY( -50% );
27
  }
28
 
29
- @media screen and ( min-width: 960px ) {
30
- width: calc( 100% - 200px );
31
- left: 180px;
 
 
 
 
 
 
 
 
32
  }
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  .page-template-modal .components-modal__header-heading-container {
@@ -44,6 +59,8 @@ body:not( .is-fullscreen-mode ) .page-template-modal {
44
 
45
  .page-template-modal__intro {
46
  text-align: center;
 
 
47
  }
48
 
49
  .page-template-modal__list {
@@ -69,12 +86,15 @@ body:not( .is-fullscreen-mode ) .page-template-modal {
69
  padding: 2em;
70
  border-radius: 4px;
71
  cursor: pointer;
 
 
72
 
73
  &:hover {
74
  background: #f3f4f5;
75
  }
76
 
77
  &:focus {
 
78
  box-shadow: 0 0 0 2px #00a0d2;
79
  outline: 2px solid transparent;
80
  outline-offset: -2px;
@@ -89,7 +109,7 @@ body:not( .is-fullscreen-mode ) .page-template-modal {
89
  background: #f6f6f6;
90
  border-radius: 4px;
91
  overflow: hidden;
92
- padding-bottom: 90%;
93
  box-sizing: content-box;
94
  position: relative;
95
  pointer-events: none;
11
  word-wrap: normal !important;
12
  }
13
 
14
+ // Modal Overlay
15
+ .page-template-modal-screen-overlay {
16
+ background-color: hsla( 0, 0%, 0%, 0.7 );
17
+ animation: none;
18
  }
19
 
20
+ // When not in fullscreen mode allow space for WP.org sidebar
21
+ body:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay {
22
 
23
  @media screen and ( min-width: 783px ) {
24
+ left: 36px;
 
 
25
  }
26
 
27
+ @media screen and ( min-width: 961px ) {
28
+ left: 160px;
29
+ }
30
+ }
31
+
32
+ // Allow space for admin bar if present and not in full screen mode
33
+ body.admin-bar:not( .is-fullscreen-mode ) .page-template-modal-screen-overlay {
34
+ top: 46px;
35
+
36
+ @media screen and ( min-width: 783px ) {
37
+ top: 32px;
38
  }
39
+
40
+ }
41
+
42
+ // Full screen modal
43
+ .page-template-modal {
44
+ width: 100%;
45
+ height: 100vh;
46
+ max-width: 800px;
47
+ animation: none;
48
  }
49
 
50
  .page-template-modal .components-modal__header-heading-container {
59
 
60
  .page-template-modal__intro {
61
  text-align: center;
62
+ margin-left: auto;
63
+ margin-right: auto;
64
  }
65
 
66
  .page-template-modal__list {
86
  padding: 2em;
87
  border-radius: 4px;
88
  cursor: pointer;
89
+ background: none;
90
+ appearance: none;
91
 
92
  &:hover {
93
  background: #f3f4f5;
94
  }
95
 
96
  &:focus {
97
+ background: #f3f4f5;
98
  box-shadow: 0 0 0 2px #00a0d2;
99
  outline: 2px solid transparent;
100
  outline-offset: -2px;
109
  background: #f6f6f6;
110
  border-radius: 4px;
111
  overflow: hidden;
112
+ padding-bottom: 133.33%;
113
  box-sizing: content-box;
114
  position: relative;
115
  pointer-events: none;
starter-page-templates/page-template-modal/utils/tracking.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Ensure Tracks Library
2
+ window._tkq = window._tkq || [];
3
+
4
+ let tracksIdentity = null;
5
+
6
+ /**
7
+ * Populate `identity` on WPCOM and ATOMIC to enable tracking.
8
+ * Always disabled for regular self-hosted installations.
9
+ */
10
+ export const initializeWithIdentity = identity => {
11
+ tracksIdentity = identity;
12
+ window._tkq.push( [ 'identifyUser', identity.userid, identity.username ] );
13
+ };
14
+
15
+ export const trackView = ( segment_id, vertical_id ) => {
16
+ if ( ! tracksIdentity ) {
17
+ return;
18
+ }
19
+ window._tkq.push( [
20
+ 'recordEvent',
21
+ 'a8c_full_site_editing_template_selector_view',
22
+ {
23
+ blog_id: tracksIdentity.blogid,
24
+ segment_id,
25
+ vertical_id,
26
+ },
27
+ ] );
28
+ };
29
+
30
+ export const trackDismiss = ( segment_id, vertical_id ) => {
31
+ if ( ! tracksIdentity ) {
32
+ return;
33
+ }
34
+ window._tkq.push( [
35
+ 'recordEvent',
36
+ 'a8c_full_site_editing_template_selector_dismiss',
37
+ {
38
+ blog_id: tracksIdentity.blogid,
39
+ segment_id,
40
+ vertical_id,
41
+ },
42
+ ] );
43
+ };
44
+
45
+ export const trackSelection = ( segment_id, vertical_id, template ) => {
46
+ if ( ! tracksIdentity ) {
47
+ return;
48
+ }
49
+ window._tkq.push( [
50
+ 'recordEvent',
51
+ 'a8c_full_site_editing_template_selector_template_selected',
52
+ {
53
+ blog_id: tracksIdentity.blogid,
54
+ segment_id,
55
+ vertical_id,
56
+ template,
57
+ },
58
+ ] );
59
+ };