Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement multi-theme system #28131

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 37 additions & 33 deletions lib/full-site-editing/block-templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ function _gutenberg_build_template_result_from_file( $template_file, $template_t

$theme = wp_get_theme()->get_stylesheet();
$template = new WP_Block_Template();
$template->id = $theme . '//' . $template_file['slug'];
$template->theme = $theme;
$template->id = $template_file['slug'];
$template->theme = array( $theme );
$template->content = file_get_contents( $template_file['path'] );
$template->slug = $template_file['slug'];
$template->is_custom = false;
Expand Down Expand Up @@ -153,12 +153,10 @@ function _gutenberg_build_template_result_from_post( $post ) {
return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'gutenberg' ) );
}

$theme = $terms[0]->name;

$template = new WP_Block_Template();
$template->wp_id = $post->ID;
$template->id = $theme . '//' . $post->post_name;
$template->theme = $theme;
$template->id = $post->post_name;
$template->theme = array();
$template->content = $post->post_content;
$template->slug = $post->post_name;
$template->is_custom = true;
Expand All @@ -167,6 +165,10 @@ function _gutenberg_build_template_result_from_post( $post ) {
$template->title = $post->post_title;
$template->status = $post->post_status;

foreach ( $terms as $term ) {
$template->theme[] = $term->slug;
}

return $template;
}

Expand All @@ -192,7 +194,7 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'field' => 'slug',
'terms' => wp_get_theme()->get_stylesheet(),
),
),
Expand Down Expand Up @@ -223,7 +225,7 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t
$template_files = _gutenberg_get_template_files( $template_type );
foreach ( $template_files as $template_file ) {
$is_custom = array_search(
wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'],
$template_file['slug'],
array_column( $query_result, 'id' ),
true
);
Expand All @@ -242,27 +244,24 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t
/**
* Retrieves a single unified template object using its id.
*
* @param string $id Template unique identifier (example: theme|slug).
* @param string $slug Template unique identifier (example: theme|slug).
* @param array $template_type wp_template or wp_template_part.
*
* @return WP_Block_Template|null Template.
*/
function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) {
$parts = explode( '//', $id, 2 );
if ( count( $parts ) < 2 ) {
return null;
}
list( $theme, $slug ) = $parts;
function gutenberg_get_block_template( $slug, $template_type = 'wp_template' ) {
$theme = wp_get_theme()->get_stylesheet();
$wp_query_args = array(
'name' => $slug,
// Can't use 'name' because tax_query won't work.
'post_name__in' => array( $slug ),
'post_type' => $template_type,
'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ),
'posts_per_page' => 1,
'no_found_rows' => true,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'field' => 'slug',
'terms' => $theme,
),
),
Expand All @@ -278,11 +277,9 @@ function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) {
}
}

if ( wp_get_theme()->get_stylesheet() === $theme ) {
$template_file = _gutenberg_get_template_file( $template_type, $slug );
if ( null !== $template_file ) {
return _gutenberg_build_template_result_from_file( $template_file, $template_type );
}
$template_file = _gutenberg_get_template_file( $template_type, $slug );
if ( null !== $template_file ) {
return _gutenberg_build_template_result_from_file( $template_file, $template_type );
}

return null;
Expand All @@ -303,18 +300,25 @@ function gutenberg_filter_wp_template_unique_post_slug( $slug, $post_ID, $post_s
}

// Template slugs must be unique within the same theme.
$theme = get_the_terms( $post_ID, 'wp_theme' )[0]->slug;
$tax_query = array(
'relation' => 'OR',
);
$terms = get_the_terms( $post_ID, 'wp_theme' );
foreach ( $terms as $term ) {
$tax_query[] = array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $term->slug,
);
}

$check_query_args = array(
'post_name' => $slug,
// Can't use 'name' because tax_query won't work.
'post_name__in' => array( $slug ),
'post_type' => $post_type,
'posts_per_page' => 1,
'post__not_in' => $post_ID,
'tax_query' => array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => $theme,
),
'tax_query' => $tax_query,
'no_found_rows' => true,
);
$check_query = new WP_Query( $check_query_args );
Expand All @@ -323,10 +327,10 @@ function gutenberg_filter_wp_template_unique_post_slug( $slug, $post_ID, $post_s
if ( count( $posts ) > 0 ) {
$suffix = 2;
do {
$query_args = $check_query_args;
$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
$query_args['post_name'] = $alt_post_name;
$query = new WP_Query( $check_query_args );
$query_args = $check_query_args;
$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
$query_args['post_name__in'][0] = $alt_post_name;
$query = new WP_Query( $query_args );
$suffix++;
} while ( count( $query->get_posts() ) > 0 );
$slug = $alt_post_name;
Expand Down
4 changes: 2 additions & 2 deletions lib/full-site-editing/class-wp-block-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class WP_Block_Template {
public $type;

/**
* Theme.
* Theme(s).
*
* @var string
* @var array
*/
public $theme;

Expand Down
124 changes: 124 additions & 0 deletions lib/full-site-editing/switch-theme.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
/**
* Theme switcher.
*
* @package gutenberg
*/

class WP_Switch_Theme_Page
{
private $title;

private $themes;

private $theme_slugs;

public function __construct() {
add_action( 'init', array( $this, 'init' ) );
add_action( 'admin_menu', array( $this, 'menu' ) );
}

public function init() {
if ( ! gutenberg_is_fse_theme() ) {
return;
}

$this->themes = array();
$current = wp_get_theme()->get_stylesheet();

foreach ( wp_get_themes() as $theme ) {
if ( is_readable( $theme->stylesheet_dir . '/block-templates/index.html' ) && $theme->stylesheet !== $current ) {
$this->themes[] = $theme;
$this->theme_slugs[] = $theme->stylesheet;
}
}

$this->title = __( 'Switch Theme', 'gutenberg' );
}

public function callback() {
if ( ! gutenberg_is_fse_theme() || ! current_user_can( 'switch_themes' ) ) {
return;
}

echo '<div class="wrap">';
echo '<h2>' . $this->title . '</h2>';
echo '<form method="post" action="">';

if ( isset( $_POST['switch_theme_2'] ) && in_array( $_POST['switch_theme_2'], $this->theme_slugs ) ) {

$keep_templates = array();
$keep_template_parts = array();

foreach ( $_POST as $key => $value ) {

if ( $value && strpos( $key, 'keep_template_' ) === 0 ) {
$keep_templates[] = substr( $key, 14 );
}
if ( $value && strpos( $key, 'keep_template-part_' ) === 0 ) {
$keep_template_parts[] = substr( $key, 19 );
}
}

foreach ( $keep_templates as $template ) {
$template = gutenberg_get_block_template( $template, 'wp_template');

foreach ( parse_blocks( $template->content ) as $block ) {
if ( 'core/template-part' === $block['blockName'] && ! empty( $block['attrs']['slug'] ) && ! in_array( $block['attrs']['slug'], $keep_template_parts ) ) {
$keep_template_parts[] = $block['attrs']['slug'];
}
}

if ( $template->wp_id ) {
wp_set_post_terms( $template->wp_id, esc_sql( $_POST['switch_theme_2'] ), 'wp_theme', true );
}
}

foreach ( $keep_template_parts as $template_part ) {
$template_part = gutenberg_get_block_template( $template_part, 'wp_template_part');

if ( $template_part->wp_id ) {
wp_set_post_terms( $template_part->wp_id, esc_sql( $_POST['switch_theme_2'] ), 'wp_theme', true );
}
}

// Temporary
echo '<p>Done. Now activating new theme...</p>';

} else if ( isset( $_POST['switch_theme'] ) && in_array( $_POST['switch_theme'], $this->theme_slugs ) ) {
echo '<p>' . __( 'Next, select which templates and template parts to keep from your current theme.', 'gutenberg' ) . '</p>';
echo '<p>' . __( 'Templates:', 'gutenberg' ) . '</p>';

foreach ( gutenberg_get_block_templates( array(), 'wp_template' ) as $template ) {
printf( '<input type="checkbox" id="keep_template_%1$s" name="keep_template_%1$s"><label for="keep_template_%1$s">%2$s</label><br>', $template->id, $template->title );
}

echo '<p>' . __( 'Template Parts:', 'gutenberg' ) . '</p>';

foreach ( gutenberg_get_block_templates( array(), 'wp_template_part' ) as $template_part ) {
printf( '<input type="checkbox" id="keep_template-part_%1$s" name="keep_template-part_%1$s"><label for="keep_template-part_%1$s">%2$s</label><br>', $template_part->id, $template_part->title );
}

printf( '<input type="hidden" name="switch_theme_2" value="%s">', esc_attr( $_POST['switch_theme'] ) );

} else {
echo '<p>' . __( 'First, select another full site editing theme to switch to.', 'gutenberg' ) . '</p>';

foreach ( $this->themes as $theme ) {
printf( '<input type="radio" id="%1$s" name="switch_theme" value="%1$s"><label for="%1$s">%2$s</label><br>', $theme->stylesheet, $theme->name );
}
}

submit_button();
echo '</form></div>';
}

public function menu() {
if ( ! gutenberg_is_fse_theme() ) {
return;
}

add_submenu_page( 'themes.php', $this->title, $this->title, 'switch_themes', 'gutenberg_switch_theme', array( $this, 'callback' ) );
}
}
new WP_Switch_Theme_Page();
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/full-site-editing/template-loader.php';
require __DIR__ . '/full-site-editing/edit-site-page.php';
require __DIR__ . '/full-site-editing/edit-site-export.php';
require __DIR__ . '/full-site-editing/switch-theme.php';

require __DIR__ . '/blocks.php';
require __DIR__ . '/client-assets.php';
Expand Down
10 changes: 5 additions & 5 deletions lib/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
*/
function _gutenberg_migrate_database() {
// The default value used here is the first version before migrations were added.
$gutenberg_installed_version = get_option( '_GUTENBERG_VERSION_MIGRATION', '9.7.0' );
$gutenberg_installed_version = get_option( 'gutenberg_version_migration', '9.7.0' );

if ( _GUTENBERG_VERSION_MIGRATION !== $gutenberg_installed_version ) {
if ( version_compare( $gutenberg_installed_version, '9.8.0', '<' ) ) {
_gutenberg_migrate_remove_fse_drafts();
}

update_option( '_GUTENBERG_VERSION_MIGRATION', _GUTENBERG_VERSION_MIGRATION );
update_option( 'gutenberg_version_migration', _GUTENBERG_VERSION_MIGRATION );
}
}

Expand All @@ -37,7 +37,7 @@ function _gutenberg_migrate_database() {
*/
function _gutenberg_migrate_remove_fse_drafts() {
// Delete auto-draft templates and template parts.
$delete_query = new WP_QUERY(
$delete_query = new WP_Query(
array(
'post_status' => array( 'auto-draft' ),
'post_type' => array( 'wp_template', 'wp_template_part' ),
Expand All @@ -49,9 +49,9 @@ function _gutenberg_migrate_remove_fse_drafts() {
}

// Delete _wp_file_based term.
$term = get_term_by( 'name', '_wp_file_based', 'wp-theme' );
$term = get_term_by( 'name', '_wp_file_based', 'wp_theme' );
if ( $term ) {
wp_delete_term( $term->term_id, 'wp-theme' );
wp_delete_term( $term->term_id, 'wp_theme' );
}
}

Expand Down
3 changes: 0 additions & 3 deletions packages/block-library/src/template-part/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
"slug": {
"type": "string"
},
"theme": {
"type": "string"
},
"tagName": {
"type": "string",
"default": "div"
Expand Down
8 changes: 4 additions & 4 deletions packages/block-library/src/template-part/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ import TemplatePartPlaceholder from './placeholder';
import TemplatePartSelection from './selection';

export default function TemplatePartEdit( {
attributes: { slug, theme, tagName: TagName = 'div' },
attributes: { slug, tagName: TagName = 'div' },
setAttributes,
clientId,
} ) {
const templatePartId = theme + '//' + slug;
const templatePartId = slug;

// Set the postId block attribute if it did not exist,
// but wait until the inner blocks have loaded to allow
Expand All @@ -39,11 +39,11 @@ export default function TemplatePartEdit( {
( select ) => {
const { getBlocks } = select( 'core/block-editor' );
const entityRecord =
theme && slug
slug
? select( 'core' ).getEntityRecord(
'postType',
'wp_template_part',
theme + '//' + slug
slug
)
: null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default function TemplatePartPlaceholder( {
);
setAttributes( {
slug: templatePart.slug,
theme: templatePart.theme,
} );
}, [ setAttributes ] );

Expand Down
Loading