diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 616f897fc60a9..9dfe19437b0c1 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -6,6 +6,10 @@ - Increase the minimum Node.js version to 14 and minimum npm version to 6.14.4 ([#43141](https://github.com/WordPress/gutenberg/pull/43141)). +### New Feature + +- Add `--no-plugin` flag to allow scaffolding of a block in an existing plugin ([#41642](https://github.com/WordPress/gutenberg/pull/41642)) + ## 3.6.0 (2022-07-13) ### Enhancement diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 1b58f4265d300..acb584ed3face 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -41,6 +41,7 @@ Options: ```bash -V, --version output the version number -t, --template project template type name; allowed values: "static" (default), "es5", the name of an external npm package, or the path to a local directory +--no-plugin scaffold block files only --namespace internal namespace for the block name --title display title for the block and the WordPress plugin --short-description short description for the block and the WordPress plugin @@ -77,6 +78,13 @@ $ npx @wordpress/create-block --template ./path/to/template-directory $ npx @wordpress/create-block --help ``` +5. No plugin mode – it is also possible to scaffold only block files into the current directory. + + +```bash +$ npx @wordpress/create-block --no-plugin +``` + When you scaffold a block, you must provide at least a `slug` name, the `namespace` which usually corresponds to either the `theme` or `plugin` name. In most cases, we recommended pairing blocks with WordPress plugins rather than themes, because only using plugin ensures that all blocks still work when your theme changes. ## Available Commands diff --git a/packages/create-block/lib/index.js b/packages/create-block/lib/index.js index 3ceeb76310bbf..adcf714559305 100644 --- a/packages/create-block/lib/index.js +++ b/packages/create-block/lib/index.js @@ -58,10 +58,12 @@ program 'disable integration with `@wordpress/scripts` package' ) .option( '--wp-env', 'enable integration with `@wordpress/env` package' ) + .option( '--no-plugin', 'scaffold only block files' ) .action( async ( slug, { + plugin, category, namespace, shortDescription: description, @@ -77,6 +79,7 @@ program const defaultValues = getDefaultValues( pluginTemplate ); const optionsValues = pickBy( { + plugin, category, description, namespace, @@ -99,7 +102,9 @@ program } else { log.info( '' ); log.info( - "Let's customize your WordPress plugin with blocks:" + plugin + ? "Let's customize your WordPress plugin with blocks:" + : "Let's add a new block to your existing WordPress plugin:" ); const filterOptionsProvided = ( { name } ) => @@ -114,33 +119,39 @@ program ] ).filter( filterOptionsProvided ); const blockAnswers = await inquirer.prompt( blockPrompts ); - const pluginAnswers = await inquirer - .prompt( { - type: 'confirm', - name: 'configurePlugin', - message: - 'Do you want to customize the WordPress plugin?', - default: false, - } ) - .then( async ( { configurePlugin } ) => { - if ( ! configurePlugin ) { - return {}; - } + const pluginAnswers = plugin + ? await inquirer + .prompt( { + type: 'confirm', + name: 'configurePlugin', + message: + 'Do you want to customize the WordPress plugin?', + default: false, + } ) + .then( async ( { configurePlugin } ) => { + if ( ! configurePlugin ) { + return {}; + } + + const pluginPrompts = getPrompts( + pluginTemplate, + [ + 'pluginURI', + 'version', + 'author', + 'license', + 'licenseURI', + 'domainPath', + 'updateURI', + ] + ).filter( filterOptionsProvided ); + const result = await inquirer.prompt( + pluginPrompts + ); + return result; + } ) + : {}; - const pluginPrompts = getPrompts( pluginTemplate, [ - 'pluginURI', - 'version', - 'author', - 'license', - 'licenseURI', - 'domainPath', - 'updateURI', - ] ).filter( filterOptionsProvided ); - const result = await inquirer.prompt( - pluginPrompts - ); - return result; - } ); await scaffold( pluginTemplate, { ...defaultValues, ...optionsValues, diff --git a/packages/create-block/lib/init-block.js b/packages/create-block/lib/init-block.js index b02aaf142a816..fe0b50209347b 100644 --- a/packages/create-block/lib/init-block.js +++ b/packages/create-block/lib/init-block.js @@ -15,6 +15,7 @@ const { writeOutputTemplate } = require( './output' ); async function initBlockJSON( { $schema, apiVersion, + plugin, slug, namespace, title, @@ -33,7 +34,9 @@ async function initBlockJSON( { info( '' ); info( 'Creating a "block.json" file.' ); - const outputFile = join( process.cwd(), slug, folderName, 'block.json' ); + const outputFile = plugin + ? join( process.cwd(), slug, folderName, 'block.json' ) + : join( process.cwd(), slug, 'block.json' ); await makeDir( dirname( outputFile ) ); await writeFile( outputFile, @@ -65,15 +68,17 @@ async function initBlockJSON( { module.exports = async function ( outputTemplates, view ) { await Promise.all( - Object.keys( outputTemplates ).map( - async ( outputFile ) => - await writeOutputTemplate( - outputTemplates[ outputFile ], - join( view.folderName, outputFile ), - view - ) - ) - ); + Object.keys( outputTemplates ).map( async ( outputFile ) => { + const pathName = view.plugin + ? join( view.folderName, outputFile ) + : join( process.cwd(), view.slug, outputFile ); + await writeOutputTemplate( + outputTemplates[ outputFile ], + pathName, + view + ); + } ) + ); await initBlockJSON( view ); }; diff --git a/packages/create-block/lib/output.js b/packages/create-block/lib/output.js index 9671a52bb20c3..32b121b89f71d 100644 --- a/packages/create-block/lib/output.js +++ b/packages/create-block/lib/output.js @@ -13,11 +13,9 @@ const writeOutputAsset = async ( inputFile, outputFile, view ) => { }; const writeOutputTemplate = async ( inputFile, outputFile, view ) => { - // Output files can have names that depend on the slug provided. - const outputFilePath = join( - view.slug, - outputFile.replace( /\$slug/g, view.slug ) - ); + const outputFilePath = view.plugin + ? join( view.slug, outputFile.replace( /\$slug/g, view.slug ) ) + : outputFile; await makeDir( dirname( outputFilePath ) ); writeFile( outputFilePath, render( inputFile, view ) ); }; diff --git a/packages/create-block/lib/prompts.js b/packages/create-block/lib/prompts.js index 26f19ab2718bd..9807f2a61c9e1 100644 --- a/packages/create-block/lib/prompts.js +++ b/packages/create-block/lib/prompts.js @@ -8,7 +8,7 @@ const slug = { type: 'input', name: 'slug', message: - 'The block slug used for identification (also the plugin and output folder name):', + 'The block slug used for identification (also the output folder name):', validate( input ) { if ( ! /^[a-z][a-z0-9\-]*$/.test( input ) ) { return 'Invalid block slug specified. Block slug can contain only lowercase alphanumeric characters or dashes, and start with a letter.'; diff --git a/packages/create-block/lib/scaffold.js b/packages/create-block/lib/scaffold.js index a342a807eec2f..495585a896233 100644 --- a/packages/create-block/lib/scaffold.js +++ b/packages/create-block/lib/scaffold.js @@ -10,7 +10,7 @@ const initBlock = require( './init-block' ); const initPackageJSON = require( './init-package-json' ); const initWPScripts = require( './init-wp-scripts' ); const initWPEnv = require( './init-wp-env' ); -const { code, info, success } = require( './log' ); +const { code, info, success, error } = require( './log' ); const { writeOutputAsset, writeOutputTemplate } = require( './output' ); module.exports = async ( @@ -18,6 +18,7 @@ module.exports = async ( { $schema, apiVersion, + plugin, namespace, slug, title, @@ -47,12 +48,29 @@ module.exports = async ( slug = slug.toLowerCase(); namespace = namespace.toLowerCase(); + /** + * --no-plugin relies on the used template supporting the [blockTemplatesPath property](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/#blocktemplatespath). + * If the blockOutputTemplates object has no properties, we can assume that there was a custom --template passed that + * doesn't support it. + */ + if ( ! plugin && Object.keys( blockOutputTemplates ) < 1 ) { + error( + 'No block files found in the template. Please ensure that the template supports the blockTemplatesPath property.' + ); + return; + } + info( '' ); - info( `Creating a new WordPress plugin in the "${ slug }" directory.` ); + info( + plugin + ? `Creating a new WordPress plugin in the ${ slug } directory.` + : `Creating a new block in the ${ slug } directory.` + ); const view = { $schema, apiVersion, + plugin, namespace, namespaceSnakeCase: snakeCase( namespace ), slug, @@ -83,16 +101,18 @@ module.exports = async ( style, }; - await Promise.all( - Object.keys( pluginOutputTemplates ).map( - async ( outputFile ) => - await writeOutputTemplate( - pluginOutputTemplates[ outputFile ], - outputFile, - view - ) - ) - ); + if ( plugin ) { + await Promise.all( + Object.keys( pluginOutputTemplates ).map( + async ( outputFile ) => + await writeOutputTemplate( + pluginOutputTemplates[ outputFile ], + outputFile, + view + ) + ) + ); + } await Promise.all( Object.keys( outputAssets ).map( @@ -107,21 +127,26 @@ module.exports = async ( await initBlock( blockOutputTemplates, view ); - await initPackageJSON( view ); - - if ( wpScripts ) { - await initWPScripts( view ); - } + if ( plugin ) { + await initPackageJSON( view ); + if ( wpScripts ) { + await initWPScripts( view ); + } - if ( wpEnv ) { - await initWPEnv( view ); + if ( wpEnv ) { + await initWPEnv( view ); + } } info( '' ); + success( - `Done: WordPress plugin "${ title }" bootstrapped in the "${ slug }" directory.` + plugin + ? `Done: WordPress plugin ${ title } bootstrapped in the ${ slug } directory.` + : `Done: Block "${ title }" bootstrapped in the ${ slug }directory.` ); - if ( wpScripts ) { + + if ( plugin && wpScripts ) { info( '' ); info( 'You can run several commands inside:' ); info( '' ); @@ -145,18 +170,18 @@ module.exports = async ( info( '' ); code( ' $ npm run packages-update' ); info( ' Updates WordPress packages to the latest version.' ); + info( '' ); + info( 'To enter the directory type:' ); + info( '' ); + code( ` $ cd ${ slug }` ); } - info( '' ); - info( 'To enter the directory type:' ); - info( '' ); - code( ` $ cd ${ slug }` ); - if ( wpScripts ) { + if ( plugin && wpScripts ) { info( '' ); info( 'You can start development with:' ); info( '' ); code( ' $ npm start' ); } - if ( wpEnv ) { + if ( plugin && wpEnv ) { info( '' ); info( 'You can start WordPress with:' ); info( '' );