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

Add Export (Clone) to site editor #292

Merged
merged 11 commits into from
Apr 3, 2023
42 changes: 40 additions & 2 deletions admin/class-create-block-theme-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ class Create_Block_Theme_Admin {
public function __construct() {
add_action( 'admin_menu', array( $this, 'create_admin_menu' ) );
add_action( 'admin_init', array( $this, 'blockbase_save_theme' ) );
add_action( 'enqueue_block_editor_assets', array( $this, 'create_block_theme_enqueue' ) );
add_action( 'rest_api_init', array( $this, 'register_theme_export' ) );
}

function create_block_theme_enqueue() {
$asset_file = include( plugin_dir_path( dirname( __FILE__ ) ) . 'build/editor.asset.php' );

wp_register_script(
'create-block-theme-slot-fill',
plugins_url( 'build/editor.js', dirname( __FILE__ ) ),
$asset_file['dependencies'],
$asset_file['version']
);
wp_enqueue_script(
'create-block-theme-slot-fill',
);
}

function create_admin_menu() {
Expand Down Expand Up @@ -187,9 +203,31 @@ function clone_theme( $theme, $screenshot ) {
header( 'Content-Disposition: attachment; filename=' . $theme['slug'] . '.zip' );
header( 'Content-Length: ' . filesize( $filename ) );
flush();
echo readfile( $filename );
die();
readfile( $filename );
unlink( $filename );
exit;
}

function rest_export_theme( $request ) {
$theme = $request->get_params();
$this->clone_theme( $theme, null );
}

public function register_theme_export() {
register_rest_route(
'create-block-theme/v1',
'/export',
array(
'methods' => 'POST',
'callback' => array( $this, 'rest_export_theme' ),
'permission_callback' => function () {
return true;
// return current_user_can( 'edit_theme_options' );
jffng marked this conversation as resolved.
Show resolved Hide resolved
},
)
);
}

/**
* Create a child theme of the activated theme
*/
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"simple-git": "^3.14.1"
},
"scripts": {
"build": "wp-scripts build",
"build": "wp-scripts build src/index.js src/editor.js",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:css:fix": "npm run lint:css -- --fix",
Expand All @@ -47,7 +47,7 @@
"lint:php": "composer run-script lint",
"lint:php:fix": "composer run-script format",
"packages-update": "wp-scripts packages-update",
"start": "wp-scripts start",
"start": "wp-scripts start src/index.js src/editor.js",
"update-version": "node update-version-and-changelog.js",
"prepare": "husky install"
},
Expand Down
154 changes: 154 additions & 0 deletions src/editor.js
jffng marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { registerPlugin } from '@wordpress/plugins';
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-site';
import { blockDefault } from '@wordpress/icons';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we should use this icon

Copy link
Contributor Author

@jffng jffng Mar 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated to use the tool icon but I'm not sure about this either, it's also rather generic.

import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
Button,
__experimentalVStack as VStack,
__experimentalText as Text,
__experimentalHeading as Heading,
PanelBody,
TextControl,
} from '@wordpress/components';
import { store as noticesStore } from '@wordpress/notices';
import { useDispatch, useSelect } from '@wordpress/data';

const ExportTheme = () => {
const { createErrorNotice } = useDispatch( noticesStore );
const [ theme, setTheme ] = useState( {
name: '',
description: '',
uri: '',
author: '',
author_uri: '',
} );

useSelect( ( select ) => {
const themeData = select( 'core' ).getCurrentTheme();
setTheme( {
name: themeData.name.raw,
description: themeData.description.raw,
author: themeData.author.raw,
author_uri: themeData.author_uri.raw,
theme_uri: themeData.theme_uri.raw,
} );
}, [] );

const handleSubmit = () => {
fetch( '/wp-json/create-block-theme/v1/export', {
jffng marked this conversation as resolved.
Show resolved Hide resolved
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( theme ),
} )
.then( ( response ) => response.blob() )
jffng marked this conversation as resolved.
Show resolved Hide resolved
.then( ( blob ) => {
const url = URL.createObjectURL( blob );
window.location.href = url;
jffng marked this conversation as resolved.
Show resolved Hide resolved
} )
.catch( ( error ) => {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __(
'An error occurred while attempting to export the theme.'
);
createErrorNotice( errorMessage, { type: 'snackbar' } );
} );
};

return (
<PanelBody>
<Heading>{ __( 'Export', 'create-block-theme' ) }</Heading>
<VStack>
<Text variant="muted">
{ __(
"Make any changes to the current theme's metadata and export as a new theme.",
'create-block-theme'
) }
</Text>
<TextControl
label={ __( 'Theme name', 'create-block-theme' ) }
value={ theme.name }
onChange={ ( value ) =>
setTheme( { ...theme, name: value } )
}
placeholder={ __( 'Theme name', 'create-block-theme' ) }
/>
<TextControl
label={ __( 'Theme description', 'create-block-theme' ) }
value={ theme.description }
onChange={ ( value ) =>
setTheme( { ...theme, description: value } )
}
placeholder={ __(
'A short description of the theme',
'create-block-theme'
) }
/>
<TextControl
label={ __( 'Theme URI', 'create-block-theme' ) }
value={ theme.uri }
onChange={ ( value ) =>
setTheme( { ...theme, uri: value } )
}
placeholder={ __(
'https://github.com/wordpress/twentytwentytwo/',
jffng marked this conversation as resolved.
Show resolved Hide resolved
'create-block-theme'
) }
/>
<TextControl
label={ __( 'Author', 'create-block-theme' ) }
value={ theme.author }
onChange={ ( value ) =>
setTheme( { ...theme, author: value } )
}
placeholder={ __(
'the WordPress team',
'create-block-theme'
) }
/>
<TextControl
label={ __( 'Author URI', 'create-block-theme' ) }
value={ theme.author_uri }
onChange={ ( value ) =>
setTheme( { ...theme, author_uri: value } )
}
placeholder={ __(
'https://wordpress.org/',
'create-block-theme'
) }
/>
jffng marked this conversation as resolved.
Show resolved Hide resolved
<Button variant="secondary" onClick={ handleSubmit }>
jffng marked this conversation as resolved.
Show resolved Hide resolved
{ __( 'Export', 'create-block-theme' ) }
</Button>
</VStack>
</PanelBody>
);
};

const CreateBlockThemePlugin = () => {
return (
<>
<PluginSidebarMoreMenuItem
target="create-block-theme-sidebar"
icon={ blockDefault }
>
{ __( 'Create Block Theme' ) }
</PluginSidebarMoreMenuItem>
<PluginSidebar
name="create-block-theme-sidebar"
icon={ blockDefault }
title={ __( 'Create Block Theme' ) }
>
<ExportTheme />
</PluginSidebar>
</>
);
};

registerPlugin( 'cbt-plugin-sidebar', {
render: CreateBlockThemePlugin,
} );