From a4285d13fa1337b07aca255333c7f01eccc635a7 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 22 Sep 2019 18:18:29 +0200 Subject: [PATCH 1/6] Introduce wp_template post type. --- lib/experiments-page.php | 12 ++++++ lib/load.php | 1 + lib/templates.php | 88 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 lib/templates.php diff --git a/lib/experiments-page.php b/lib/experiments-page.php index a0db70232f2c20..1d7d1e4a704c83 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -75,6 +75,17 @@ function gutenberg_initialize_experiments_settings() { 'id' => 'gutenberg-block-directory', ) ); + add_settings_field( + 'gutenberg-full-site-editing', + __( 'Full Site Editing', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Enable Full Site Editing', 'gutenberg' ), + 'id' => 'gutenberg-full-site-editing', + ) + ); register_setting( 'gutenberg-experiments', 'gutenberg-experiments' @@ -126,6 +137,7 @@ function gutenberg_experiments_editor_settings( $settings ) { '__experimentalEnableLegacyWidgetBlock' => $experiments_exist ? array_key_exists( 'gutenberg-widget-experiments', get_option( 'gutenberg-experiments' ) ) : false, '__experimentalEnableMenuBlock' => $experiments_exist ? array_key_exists( 'gutenberg-menu-block', get_option( 'gutenberg-experiments' ) ) : false, '__experimentalBlockDirectory' => $experiments_exist ? array_key_exists( 'gutenberg-block-directory', get_option( 'gutenberg-experiments' ) ) : false, + '__experimentalEnableFullSiteEditing' => $experiments_exist ? array_key_exists( 'gutenberg-full-site-editing', get_option( 'gutenberg-experiments' ) ) : false, ); return array_merge( $settings, $experiments_settings ); diff --git a/lib/load.php b/lib/load.php index 7915e4a3e5fe53..a0996f3b94f4ff 100644 --- a/lib/load.php +++ b/lib/load.php @@ -40,6 +40,7 @@ require dirname( __FILE__ ) . '/compat.php'; require dirname( __FILE__ ) . '/blocks.php'; +require dirname( __FILE__ ) . '/templates.php'; require dirname( __FILE__ ) . '/client-assets.php'; require dirname( __FILE__ ) . '/demo.php'; require dirname( __FILE__ ) . '/widgets.php'; diff --git a/lib/templates.php b/lib/templates.php new file mode 100644 index 00000000000000..55a574e6f55777 --- /dev/null +++ b/lib/templates.php @@ -0,0 +1,88 @@ + __( 'Templates', 'gutenberg' ), + 'singular_name' => __( 'Template', 'gutenberg' ), + 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), + 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), + 'add_new_item' => __( 'Add New Template', 'gutenberg' ), + 'new_item' => __( 'New Template', 'gutenberg' ), + 'edit_item' => __( 'Edit Template', 'gutenberg' ), + 'view_item' => __( 'View Template', 'gutenberg' ), + 'all_items' => __( 'All Templates', 'gutenberg' ), + 'search_items' => __( 'Search Templates', 'gutenberg' ), + 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), + 'not_found' => __( 'No templates found.', 'gutenberg' ), + 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), + 'archives' => __( 'Template archives', 'gutenberg' ), + 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), + 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), + 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), + 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), + 'items_list' => __( 'Templates list', 'gutenberg' ), + ); + + $args = array( + 'labels' => $labels, + 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), + 'public' => false, + 'has_archive' => false, + 'show_ui' => true, + 'show_in_menu' => 'themes.php', + 'show_in_admin_bar' => false, + 'show_in_rest' => true, + 'rest_base' => 'templates', + 'capability_type' => array( 'template', 'templates' ), + 'map_meta_cap' => true, + 'supports' => array( + 'title', + 'editor', + 'revisions', + ), + ); + + register_post_type( 'wp_template', $args ); +} +add_action( 'init', 'gutenberg_register_template_post_type' ); + +/** + * Filters the capabilities of a user to conditionally grant them capabilities for managing 'wp_template' posts. + * + * Any user who can 'edit_theme_options' will have access. + * + * @param array $allcaps A user's capabilities. + * @return array Filtered $allcaps. + */ +function gutenberg_grant_template_caps( array $allcaps ) { + if ( isset( $allcaps['edit_theme_options'] ) ) { + $allcaps['edit_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_others_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_published_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_private_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_others_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_published_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_private_templates'] = $allcaps['edit_theme_options']; + $allcaps['publish_templates'] = $allcaps['edit_theme_options']; + $allcaps['read_private_templates'] = $allcaps['edit_theme_options']; + } + + return $allcaps; +} +add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); From 62e9d0e6cdb627e62a36b352b67db10458ac8a67 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 22 Sep 2019 18:24:56 +0200 Subject: [PATCH 2/6] Improve (temporary) admin UI for wp_template post type by exposing slug. --- lib/templates.php | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/templates.php b/lib/templates.php index 55a574e6f55777..d968d71d9c1cbf 100644 --- a/lib/templates.php +++ b/lib/templates.php @@ -86,3 +86,54 @@ function gutenberg_grant_template_caps( array $allcaps ) { return $allcaps; } add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); + +/** + * Fixes the label of the 'wp_template' admin menu entry. + */ +function gutenberg_fix_template_admin_menu_entry() { + global $submenu; + + if ( ! isset( $submenu['themes.php'] ) ) { + return; + } + + $post_type = get_post_type_object( 'wp_template' ); + foreach ( $submenu['themes.php'] as $key => $submenu_entry ) { + if ( $post_type->labels->all_items === $submenu['themes.php'][ $key ][0] ) { + $submenu['themes.php'][ $key ][0] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride + break; + } + } +} +add_action( 'admin_menu', 'gutenberg_fix_template_admin_menu_entry' ); + +/** + * Filters the 'wp_template' post type columns in the admin list table. + * + * @param array $columns Columns to display. + * @return array Filtered $columns. + */ +function gutenberg_filter_template_list_table_columns( array $columns ) { + $columns['slug'] = __( 'Slug', 'gutenberg' ); + if ( isset( $columns['date'] ) ) { + unset( $columns['date'] ); + } + return $columns; +} +add_filter( 'manage_wp_template_posts_columns', 'gutenberg_filter_template_list_table_columns' ); + +/** + * Renders column content for the 'wp_template' post type list table. + * + * @param string $column_name Column name to render. + * @param int $post_id Post ID. + */ +function gutenberg_render_template_list_table_column( $column_name, $post_id ) { + if ( 'slug' !== $column_name ) { + return; + } + + $post = get_post( $post_id ); + echo esc_html( $post->post_name ); +} +add_action( 'manage_wp_template_posts_custom_column', 'gutenberg_render_template_list_table_column', 10, 2 ); From 230a234e6297017a768216ebfbdc2c72bdf38f8a Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 22 Sep 2019 18:55:08 +0200 Subject: [PATCH 3/6] Implement template loader overrides to rely on 'wp_template' posts. --- lib/load.php | 1 + lib/template-canvas.php | 23 ++++++ lib/template-loader.php | 150 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 lib/template-canvas.php create mode 100644 lib/template-loader.php diff --git a/lib/load.php b/lib/load.php index a0996f3b94f4ff..35b49b2ead5b95 100644 --- a/lib/load.php +++ b/lib/load.php @@ -41,6 +41,7 @@ require dirname( __FILE__ ) . '/blocks.php'; require dirname( __FILE__ ) . '/templates.php'; +require dirname( __FILE__ ) . '/template-loader.php'; require dirname( __FILE__ ) . '/client-assets.php'; require dirname( __FILE__ ) . '/demo.php'; require dirname( __FILE__ ) . '/widgets.php'; diff --git a/lib/template-canvas.php b/lib/template-canvas.php new file mode 100644 index 00000000000000..a0e0da7ea01752 --- /dev/null +++ b/lib/template-canvas.php @@ -0,0 +1,23 @@ + + +> + + + + + +> + + + + + + + diff --git a/lib/template-loader.php b/lib/template-loader.php new file mode 100644 index 00000000000000..3ab8f4ea639834 --- /dev/null +++ b/lib/template-loader.php @@ -0,0 +1,150 @@ + 'wp_template', + 'post_status' => 'publish', + 'post_name__in' => $slugs, + 'orderby' => 'post_name__in', + 'posts_per_page' => 1, + ) + ); + + if ( $template_query->have_posts() ) { + $template_posts = $template_query->get_posts(); + $_wp_current_template_post = $template_posts[0]; + } + + // This file will be included instead of the theme's template file. + return gutenberg_dir_path() . 'lib/template-canvas.php'; +} + +/** + * Renders the markup for the current template. + */ +function gutenberg_render_the_template() { + global $_wp_current_template_post; + + if ( ! $_wp_current_template_post || 'wp_template' !== $_wp_current_template_post->post_type ) { + echo '

' . esc_html__( 'No matching template found', 'gutenberg' ) . '

'; + return; + } + + $content = $_wp_current_template_post->post_content; + + $content = do_blocks( $content ); + $content = wptexturize( $content ); + $content = str_replace( ']]>', ']]>', $content ); + + // Wrap block template in .wp-site-blocks to allow for specific descendant styles + // (e.g. `.wp-site-blocks > *`). + echo '
'; + echo $content; // phpcs:ignore WordPress.Security.EscapeOutput + echo '
'; +} + +/** + * Strips .php suffix from template file names. + * + * @access private + * + * @param string $template_file Template file name. + * @return string Template file name without extension. + */ +function gutenberg_strip_php_suffix( $template_file ) { + return preg_replace( '/\.php$/', '', $template_file ); +} From 915f34bbd1ba414164685c3a0646c54dd6533cda Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 22 Sep 2019 18:59:12 +0200 Subject: [PATCH 4/6] Render viewport meta tag. --- lib/template-loader.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/template-loader.php b/lib/template-loader.php index 3ab8f4ea639834..2a13cdba860c5c 100644 --- a/lib/template-loader.php +++ b/lib/template-loader.php @@ -109,6 +109,9 @@ function gutenberg_find_template( $template_file ) { $_wp_current_template_post = $template_posts[0]; } + // Add extra hooks for template canvas. + add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 ); + // This file will be included instead of the theme's template file. return gutenberg_dir_path() . 'lib/template-canvas.php'; } @@ -137,6 +140,15 @@ function gutenberg_render_the_template() { echo ''; } +/** + * Renders a 'viewport' meta tag. + * + * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. + */ +function gutenberg_viewport_meta_tag() { + echo '' . "\n"; +} + /** * Strips .php suffix from template file names. * From 3a61491dc2677b69bf7e7c81e6465d2c532bbab9 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 22 Sep 2019 19:05:50 +0200 Subject: [PATCH 5/6] Prevent deletion of fallback 'wp_template' post 'index'. --- lib/templates.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/templates.php b/lib/templates.php index d968d71d9c1cbf..1ce18b4636bfcb 100644 --- a/lib/templates.php +++ b/lib/templates.php @@ -87,6 +87,35 @@ function gutenberg_grant_template_caps( array $allcaps ) { } add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); +/** + * Filters capabilities to prevent deletion of the 'wp_template' post with slug 'index'. + * + * Similar to today's themes, this template should always exist. + * + * @param array $caps Array of the user's capabilities. + * @param string $cap Capability name. + * @param int $user_id The user ID. + * @param array $args Adds the context to the cap. Typically the object ID. + * @return array Filtered $caps. + */ +function gutenberg_prevent_index_template_deletion( $caps, $cap, $user_id, $args ) { + if ( 'delete_post' !== $cap || ! isset( $args[0] ) ) { + return $caps; + } + + $post = get_post( $args[0] ); + if ( ! $post || 'wp_template' !== $post->post_type ) { + return $caps; + } + + if ( 'index' === $post->post_name ) { + $caps[] = 'do_not_allow'; + } + + return $caps; +} +add_filter( 'map_meta_cap', 'gutenberg_prevent_index_template_deletion', 10, 4 ); + /** * Fixes the label of the 'wp_template' admin menu entry. */ From d835348f0426201feff3a2728e6a79da1b83f471 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Fri, 27 Sep 2019 10:05:44 +0200 Subject: [PATCH 6/6] Scope PR to just basic wp_template post type registration. --- lib/load.php | 1 - lib/template-canvas.php | 23 ------ lib/template-loader.php | 162 ---------------------------------------- lib/templates.php | 121 +++--------------------------- 4 files changed, 10 insertions(+), 297 deletions(-) delete mode 100644 lib/template-canvas.php delete mode 100644 lib/template-loader.php diff --git a/lib/load.php b/lib/load.php index 35b49b2ead5b95..a0996f3b94f4ff 100644 --- a/lib/load.php +++ b/lib/load.php @@ -41,7 +41,6 @@ require dirname( __FILE__ ) . '/blocks.php'; require dirname( __FILE__ ) . '/templates.php'; -require dirname( __FILE__ ) . '/template-loader.php'; require dirname( __FILE__ ) . '/client-assets.php'; require dirname( __FILE__ ) . '/demo.php'; require dirname( __FILE__ ) . '/widgets.php'; diff --git a/lib/template-canvas.php b/lib/template-canvas.php deleted file mode 100644 index a0e0da7ea01752..00000000000000 --- a/lib/template-canvas.php +++ /dev/null @@ -1,23 +0,0 @@ - - -> - - - - - -> - - - - - - - diff --git a/lib/template-loader.php b/lib/template-loader.php deleted file mode 100644 index 2a13cdba860c5c..00000000000000 --- a/lib/template-loader.php +++ /dev/null @@ -1,162 +0,0 @@ - 'wp_template', - 'post_status' => 'publish', - 'post_name__in' => $slugs, - 'orderby' => 'post_name__in', - 'posts_per_page' => 1, - ) - ); - - if ( $template_query->have_posts() ) { - $template_posts = $template_query->get_posts(); - $_wp_current_template_post = $template_posts[0]; - } - - // Add extra hooks for template canvas. - add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 ); - - // This file will be included instead of the theme's template file. - return gutenberg_dir_path() . 'lib/template-canvas.php'; -} - -/** - * Renders the markup for the current template. - */ -function gutenberg_render_the_template() { - global $_wp_current_template_post; - - if ( ! $_wp_current_template_post || 'wp_template' !== $_wp_current_template_post->post_type ) { - echo '

' . esc_html__( 'No matching template found', 'gutenberg' ) . '

'; - return; - } - - $content = $_wp_current_template_post->post_content; - - $content = do_blocks( $content ); - $content = wptexturize( $content ); - $content = str_replace( ']]>', ']]>', $content ); - - // Wrap block template in .wp-site-blocks to allow for specific descendant styles - // (e.g. `.wp-site-blocks > *`). - echo '
'; - echo $content; // phpcs:ignore WordPress.Security.EscapeOutput - echo '
'; -} - -/** - * Renders a 'viewport' meta tag. - * - * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. - */ -function gutenberg_viewport_meta_tag() { - echo '' . "\n"; -} - -/** - * Strips .php suffix from template file names. - * - * @access private - * - * @param string $template_file Template file name. - * @return string Template file name without extension. - */ -function gutenberg_strip_php_suffix( $template_file ) { - return preg_replace( '/\.php$/', '', $template_file ); -} diff --git a/lib/templates.php b/lib/templates.php index 1ce18b4636bfcb..dce2905b0ae52d 100644 --- a/lib/templates.php +++ b/lib/templates.php @@ -17,40 +17,19 @@ function gutenberg_register_template_post_type() { } $labels = array( - 'name' => __( 'Templates', 'gutenberg' ), - 'singular_name' => __( 'Template', 'gutenberg' ), - 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), - 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), - 'add_new_item' => __( 'Add New Template', 'gutenberg' ), - 'new_item' => __( 'New Template', 'gutenberg' ), - 'edit_item' => __( 'Edit Template', 'gutenberg' ), - 'view_item' => __( 'View Template', 'gutenberg' ), - 'all_items' => __( 'All Templates', 'gutenberg' ), - 'search_items' => __( 'Search Templates', 'gutenberg' ), - 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), - 'not_found' => __( 'No templates found.', 'gutenberg' ), - 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), - 'archives' => __( 'Template archives', 'gutenberg' ), - 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), - 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), - 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), - 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), - 'items_list' => __( 'Templates list', 'gutenberg' ), + 'name' => __( 'Templates', 'gutenberg' ), ); $args = array( - 'labels' => $labels, - 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), - 'public' => false, - 'has_archive' => false, - 'show_ui' => true, - 'show_in_menu' => 'themes.php', - 'show_in_admin_bar' => false, - 'show_in_rest' => true, - 'rest_base' => 'templates', - 'capability_type' => array( 'template', 'templates' ), - 'map_meta_cap' => true, - 'supports' => array( + 'labels' => $labels, + 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), + 'public' => false, + 'has_archive' => false, + 'show_in_rest' => true, + 'rest_base' => 'templates', + 'capability_type' => array( 'template', 'templates' ), + 'map_meta_cap' => true, + 'supports' => array( 'title', 'editor', 'revisions', @@ -86,83 +65,3 @@ function gutenberg_grant_template_caps( array $allcaps ) { return $allcaps; } add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); - -/** - * Filters capabilities to prevent deletion of the 'wp_template' post with slug 'index'. - * - * Similar to today's themes, this template should always exist. - * - * @param array $caps Array of the user's capabilities. - * @param string $cap Capability name. - * @param int $user_id The user ID. - * @param array $args Adds the context to the cap. Typically the object ID. - * @return array Filtered $caps. - */ -function gutenberg_prevent_index_template_deletion( $caps, $cap, $user_id, $args ) { - if ( 'delete_post' !== $cap || ! isset( $args[0] ) ) { - return $caps; - } - - $post = get_post( $args[0] ); - if ( ! $post || 'wp_template' !== $post->post_type ) { - return $caps; - } - - if ( 'index' === $post->post_name ) { - $caps[] = 'do_not_allow'; - } - - return $caps; -} -add_filter( 'map_meta_cap', 'gutenberg_prevent_index_template_deletion', 10, 4 ); - -/** - * Fixes the label of the 'wp_template' admin menu entry. - */ -function gutenberg_fix_template_admin_menu_entry() { - global $submenu; - - if ( ! isset( $submenu['themes.php'] ) ) { - return; - } - - $post_type = get_post_type_object( 'wp_template' ); - foreach ( $submenu['themes.php'] as $key => $submenu_entry ) { - if ( $post_type->labels->all_items === $submenu['themes.php'][ $key ][0] ) { - $submenu['themes.php'][ $key ][0] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride - break; - } - } -} -add_action( 'admin_menu', 'gutenberg_fix_template_admin_menu_entry' ); - -/** - * Filters the 'wp_template' post type columns in the admin list table. - * - * @param array $columns Columns to display. - * @return array Filtered $columns. - */ -function gutenberg_filter_template_list_table_columns( array $columns ) { - $columns['slug'] = __( 'Slug', 'gutenberg' ); - if ( isset( $columns['date'] ) ) { - unset( $columns['date'] ); - } - return $columns; -} -add_filter( 'manage_wp_template_posts_columns', 'gutenberg_filter_template_list_table_columns' ); - -/** - * Renders column content for the 'wp_template' post type list table. - * - * @param string $column_name Column name to render. - * @param int $post_id Post ID. - */ -function gutenberg_render_template_list_table_column( $column_name, $post_id ) { - if ( 'slug' !== $column_name ) { - return; - } - - $post = get_post( $post_id ); - echo esc_html( $post->post_name ); -} -add_action( 'manage_wp_template_posts_custom_column', 'gutenberg_render_template_list_table_column', 10, 2 );