@wordpress/create-block 4.0.1-next.d6164808d3.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
- ## 4.0.0-next.0 (2022-08-23)
5
+ ## 4.0.0 (2022-08-24)
6
6
 
7
7
  ### Breaking Change
8
8
 
@@ -11,7 +11,7 @@
11
11
  ### New Feature
12
12
 
13
13
  - Add `--no-plugin` flag to allow scaffolding of a block in an existing plugin ([#41642](https://github.com/WordPress/gutenberg/pull/41642))
14
- - Introduce the `--variant` flag to allow selection of a variant as defined in the template ([#41289](https://github.com/WordPress/gutenberg/pull/41289)).
14
+ - Introduce the `--variant` flag to allow selection of a variant as defined in the template ([#41289](https://github.com/WordPress/gutenberg/pull/41289), [#43481](https://github.com/WordPress/gutenberg/pull/43481)).
15
15
 
16
16
  ## 3.6.0 (2022-07-13)
17
17
 
package/README.md CHANGED
@@ -24,6 +24,8 @@ _(requires `node` version `14.0.0` or above, and `npm` version `6.14.4` or above
24
24
 
25
25
  It creates a WordPress plugin that you need to [install manually](https://wordpress.org/support/article/managing-plugins/#manual-plugin-installation).
26
26
 
27
+ [Watch a video introduction to create-block on Learn.wordpress.org](https://learn.wordpress.org/tutorial/using-the-create-block-tool/)
28
+
27
29
  ## Usage
28
30
 
29
31
  The following command generates a project with PHP, JS, and CSS code for registering a block with a WordPress plugin.
@@ -87,7 +89,6 @@ $ npx @wordpress/create-block --help
87
89
 
88
90
  5. No plugin mode – it is also possible to scaffold only block files into the current directory.
89
91
 
90
-
91
92
  ```bash
92
93
  $ npx @wordpress/create-block --no-plugin
93
94
  ```
@@ -144,107 +145,7 @@ _Note: You don’t need to install or configure tools like [webpack](https://web
144
145
 
145
146
  ## External Project Templates
146
147
 
147
- Are you looking for a way to share your project configuration? Creating an external project template hosted on npm or located in a local directory is possible. These npm packages can provide custom `.mustache` files that replace default files included in the tool for the WordPress plugin or/and the block. It's also possible to override default configuration values used during the scaffolding process.
148
-
149
- ### Project Template Configuration
150
-
151
- Providing the main file (`index.js` by default) for the package that returns a configuration object is mandatory. Several options allow customizing the scaffolding process.
152
-
153
- #### `pluginTemplatesPath`
154
-
155
- This optional field allows overriding file templates related to **the WordPress plugin shell**. The path points to a location with template files ending with the `.mustache` extension (nested folders are also supported). When not set, the tool uses its own set of templates.
156
-
157
- _Example:_
158
-
159
- ```js
160
- const { join } = require( 'path' );
161
-
162
- module.exports = {
163
- pluginTemplatesPath: join( __dirname, 'plugin-templates' ),
164
- };
165
- ```
166
-
167
- #### `blockTemplatesPath`
168
-
169
- This optional field allows overriding file templates related to **the individual block**. The path points to a location with template files ending with the `.mustache` extension (nested folders are also supported). When not set, the tool uses its own set of templates.
170
-
171
- _Example:_
172
-
173
- ```js
174
- const { join } = require( 'path' );
175
-
176
- module.exports = {
177
- blockTemplatesPath: join( __dirname, 'block-templates' ),
178
- };
179
- ```
180
-
181
- #### `assetsPath`
182
-
183
- This setting is useful when your template scaffolds a WordPress plugin that uses static assets like images or fonts, which should not be processed. It provides the path pointing to the location where assets are located. They will be copied to the `assets` subfolder in the generated plugin.
184
-
185
- _Example:_
186
-
187
- ```js
188
- const { join } = require( 'path' );
189
-
190
- module.exports = {
191
- assetsPath: join( __dirname, 'plugin-assets' ),
192
- };
193
- ```
194
-
195
- #### `defaultValues`
196
-
197
- It is possible to override the default template configuration using the `defaultValues` field.
198
-
199
- _Example:_
200
-
201
- ```js
202
- module.exports = {
203
- defaultValues: {
204
- slug: 'my-fantastic-block',
205
- title: 'My fantastic block',
206
- dashicon: 'palmtree',
207
- version: '1.2.3',
208
- },
209
- };
210
- ```
211
-
212
- The following configurable variables are used with the template files. Template authors can change default values to use when users don't provide their data.
213
-
214
- **Project**:
215
-
216
- - `wpScripts` (default: `true`) – enables integration with the `@wordpress/scripts` package and adds common scripts to the `package.json`.
217
- - `wpEnv` (default: `false`) – enables integration with the `@wordpress/env` package and adds the `env` script to the `package.json`.
218
- - `customScripts` (default: {}) – the list of custom scripts to add to `package.json` . It also allows overriding default scripts.
219
- - `npmDependencies` (default: `[]`) – the list of remote npm packages to be installed in the project with [`npm install`](https://docs.npmjs.com/cli/v8/commands/npm-install) when `wpScripts` is enabled.
220
- - `npmDevDependencies` (default: `[]`) – the list of remote npm packages to be installed in the project with [`npm install --save-dev`](https://docs.npmjs.com/cli/v8/commands/npm-install) when `wpScripts` is enabled.
221
-
222
- **Plugin header fields** ([learn more](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/)):
223
-
224
- - `pluginURI` (no default) – the home page of the plugin.
225
- - `version` (default: `'0.1.0'`) – the current version number of the plugin.
226
- - `author` (default: `'The WordPress Contributors'`) – the name of the plugin author(s).
227
- - `license` (default: `'GPL-2.0-or-later'`) – the short name of the plugin’s license.
228
- - `licenseURI` (default: `'https://www.gnu.org/licenses/gpl-2.0.html'`) – a link to the full text of the license.
229
- - `domainPath` (no default) – a custom domain path for the translations ([more info](https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#domain-path)).
230
- - `updateURI:` (no default) – a custom update URI for the plugin ([related dev note](https://make.wordpress.org/core/2021/06/29/introducing-update-uri-plugin-header-in-wordpress-5-8/)).
231
-
232
- **Block metadata** ([learn more](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/)):
233
-
234
- - `folderName` (default: `.`) – the location for the `block.json` file and other optional block files generated from block templates included in the folder set with the `blockTemplatesPath` setting.
235
- - `$schema` (default: `https://schemas.wp.org/trunk/block.json`) – the schema URL used for block validation.
236
- - `apiVersion` (default: `2`) – the block API version ([related dev note](https://make.wordpress.org/core/2020/11/18/block-api-version-2/)).
237
- - `slug` (no default) – the block slug used for identification in the block name.
238
- - `namespace` (default: `'create-block'`) – the internal namespace for the block name.
239
- - `title` (no default) – a display title for your block.
240
- - `description` (no default) – a short description for your block.
241
- - `dashicon` (no default) – an icon property thats makes it easier to identify a block ([available values](https://developer.wordpress.org/resource/dashicons/)).
242
- - `category` (default: `'widgets'`) – blocks are grouped into categories to help users browse and discover them. The categories provided by core are `text`, `media`, `design`, `widgets`, `theme`, and `embed`.
243
- - `attributes` (no default) – block attributes ([more details](https://developer.wordpress.org/block-editor/developers/block-api/block-attributes/)).
244
- - `supports` (no default) – optional block extended support features ([more details](https://developer.wordpress.org/block-editor/developers/block-api/block-supports/).
245
- - `editorScript` (default: `'file:./index.js'`) – an editor script definition.
246
- - `editorStyle` (default: `'file:./index.css'`) – an editor style definition.
247
- - `style` (default: `'file:./style-index.css'`) – a frontend and editor style definition.
148
+ [Click here](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/docs/external-template.md) for information on External Project Templates
248
149
 
249
150
  ## Contributing to this package
250
151
 
package/lib/index.js CHANGED
@@ -77,10 +77,22 @@ program
77
77
  await checkSystemRequirements( engines );
78
78
  try {
79
79
  const pluginTemplate = await getPluginTemplate( templateName );
80
- const defaultValues = getDefaultValues(
81
- pluginTemplate,
82
- variant
80
+ const availableVariants = Object.keys(
81
+ pluginTemplate.variants
83
82
  );
83
+ if ( variant && ! availableVariants.includes( variant ) ) {
84
+ if ( ! availableVariants.length ) {
85
+ throw new CLIError(
86
+ `"${ variant }" variant was selected. This template does not have any variants!`
87
+ );
88
+ }
89
+ throw new CLIError(
90
+ `"${ variant }" is not a valid variant for this template. Available variants are: ${ availableVariants.join(
91
+ ', '
92
+ ) }.`
93
+ );
94
+ }
95
+
84
96
  const optionsValues = Object.fromEntries(
85
97
  Object.entries( {
86
98
  plugin,
@@ -90,11 +102,14 @@ program
90
102
  title,
91
103
  wpScripts,
92
104
  wpEnv,
93
- variant,
94
105
  } ).filter( ( [ , value ] ) => value !== undefined )
95
106
  );
96
107
 
97
108
  if ( slug ) {
109
+ const defaultValues = getDefaultValues(
110
+ pluginTemplate,
111
+ variant
112
+ );
98
113
  const answers = {
99
114
  ...defaultValues,
100
115
  slug,
@@ -111,19 +126,24 @@ program
111
126
  : "Let's add a new block to your existing WordPress plugin:"
112
127
  );
113
128
 
114
- const filterOptionsProvided = ( { name } ) =>
115
- ! Object.keys( optionsValues ).includes( name );
129
+ if ( ! variant && availableVariants.length > 1 ) {
130
+ const result = await inquirer.prompt( {
131
+ type: 'list',
132
+ name: 'variant',
133
+ message:
134
+ 'The template variant to use for this block:',
135
+ choices: availableVariants,
136
+ } );
137
+ variant = result.variant;
138
+ }
116
139
 
117
- // Get the variant prompt first. This will help get the default values
118
- const variantPrompt =
119
- Object.keys( pluginTemplate.variants )?.length > 1
120
- ? getPrompts( pluginTemplate, [ 'variant' ] )
121
- : false;
122
-
123
- const variantSelection = variantPrompt
124
- ? await inquirer.prompt( variantPrompt )
125
- : false;
140
+ const defaultValues = getDefaultValues(
141
+ pluginTemplate,
142
+ variant
143
+ );
126
144
 
145
+ const filterOptionsProvided = ( { name } ) =>
146
+ ! Object.keys( optionsValues ).includes( name );
127
147
  const blockPrompts = getPrompts(
128
148
  pluginTemplate,
129
149
  [
@@ -134,9 +154,8 @@ program
134
154
  'dashicon',
135
155
  'category',
136
156
  ],
137
- variantSelection.variant
157
+ variant
138
158
  ).filter( filterOptionsProvided );
139
-
140
159
  const blockAnswers = await inquirer.prompt( blockPrompts );
141
160
 
142
161
  const pluginAnswers = plugin
@@ -163,7 +182,8 @@ program
163
182
  'licenseURI',
164
183
  'domainPath',
165
184
  'updateURI',
166
- ]
185
+ ],
186
+ variant
167
187
  ).filter( filterOptionsProvided );
168
188
  const result = await inquirer.prompt(
169
189
  pluginPrompts
@@ -175,8 +195,8 @@ program
175
195
  await scaffold( pluginTemplate, {
176
196
  ...defaultValues,
177
197
  ...optionsValues,
198
+ variant,
178
199
  ...blockAnswers,
179
- ...variantSelection,
180
200
  ...pluginAnswers,
181
201
  } );
182
202
  }
package/lib/prompts.js CHANGED
@@ -134,16 +134,8 @@ const updateURI = {
134
134
  message: 'A custom update URI for the plugin (optional):',
135
135
  };
136
136
 
137
- const variant = {
138
- type: 'list',
139
- name: 'variant',
140
- message: 'The template variant to use for this block:',
141
- choices: [],
142
- };
143
-
144
137
  module.exports = {
145
138
  slug,
146
- variant,
147
139
  namespace,
148
140
  title,
149
141
  description,
package/lib/scaffold.js CHANGED
@@ -12,10 +12,9 @@ const initWPScripts = require( './init-wp-scripts' );
12
12
  const initWPEnv = require( './init-wp-env' );
13
13
  const { code, info, success, error } = require( './log' );
14
14
  const { writeOutputAsset, writeOutputTemplate } = require( './output' );
15
- const { getTemplateVariantVars } = require( './templates' );
16
15
 
17
16
  module.exports = async (
18
- { blockOutputTemplates, pluginOutputTemplates, outputAssets, variants },
17
+ { blockOutputTemplates, pluginOutputTemplates, outputAssets },
19
18
  {
20
19
  $schema,
21
20
  apiVersion,
@@ -44,7 +43,7 @@ module.exports = async (
44
43
  editorScript,
45
44
  editorStyle,
46
45
  style,
47
- variant,
46
+ variantVars,
48
47
  }
49
48
  ) => {
50
49
  slug = slug.toLowerCase();
@@ -100,8 +99,7 @@ module.exports = async (
100
99
  editorScript,
101
100
  editorStyle,
102
101
  style,
103
- ...getTemplateVariantVars( variants, variant ),
104
- ...variants[ variant ],
102
+ ...variantVars,
105
103
  };
106
104
 
107
105
  if ( plugin ) {
@@ -146,7 +144,7 @@ module.exports = async (
146
144
  success(
147
145
  plugin
148
146
  ? `Done: WordPress plugin ${ title } bootstrapped in the ${ slug } directory.`
149
- : `Done: Block "${ title }" bootstrapped in the ${ slug }directory.`
147
+ : `Done: Block "${ title }" bootstrapped in the ${ slug } directory.`
150
148
  );
151
149
 
152
150
  if ( plugin && wpScripts ) {
@@ -34,6 +34,7 @@ registerBlockType( metadata.name, {
34
34
  */
35
35
  edit: Edit,
36
36
  {{#isStaticVariant}}
37
+
37
38
  /**
38
39
  * @see ./save.js
39
40
  */
@@ -68,32 +68,24 @@ function {{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init() {
68
68
  array(),
69
69
  filemtime( "$dir/$style_css" )
70
70
  );
71
- {{^isDynamicVariant}}
71
+
72
72
  register_block_type(
73
73
  '{{namespace}}/{{slug}}',
74
74
  array(
75
75
  'editor_script' => '{{namespace}}-{{slug}}-block-editor',
76
76
  'editor_style' => '{{namespace}}-{{slug}}-block-editor',
77
77
  'style' => '{{namespace}}-{{slug}}-block',
78
- )
79
- );
80
- {{/isDynamicVariant}}
81
- {{#isDynamicVariant}}
82
- register_block_type(
83
- '{{namespace}}/{{slug}}',
84
- array(
85
- 'editor_script' => '{{namespace}}-{{slug}}-block-editor',
86
- 'editor_style' => '{{namespace}}-{{slug}}-block-editor',
87
- 'style' => '{{namespace}}-{{slug}}-block',
78
+ {{#isDynamicVariant}}
88
79
  'render_callback' => '{{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback',
80
+ {{/isDynamicVariant}}
89
81
  )
90
82
  );
91
- {{/isDynamicVariant}}
92
83
  }
93
84
  add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' );
94
85
  {{#isDynamicVariant}}
86
+
95
87
  /**
96
- * Render callback function
88
+ * Render callback function.
97
89
  *
98
90
  * @param array $attributes The block attributes.
99
91
  * @param string $content The block content.
@@ -101,7 +93,7 @@ add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' );
101
93
  *
102
94
  * @return string The rendered output.
103
95
  */
104
- function {{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback( $atts, $content, $block) {
96
+ function {{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback( $attributes, $content, $block ) {
105
97
  ob_start();
106
98
  require plugin_dir_path( __FILE__ ) . '/template.php';
107
99
  return ob_get_clean();
@@ -94,7 +94,9 @@
94
94
  useBlockProps(),
95
95
  __( '{{title}} – hello from the editor!', '{{textdomain}}' )
96
96
  );
97
- }{{#isStaticVariant}},
97
+ },
98
+ {{#isStaticVariant}}
99
+
98
100
  /**
99
101
  * The save function defines the way in which the different attributes should be combined
100
102
  * into the final markup, which is then serialized by the block editor into `post_content`.
@@ -37,25 +37,24 @@
37
37
  *
38
38
  * @see https://developer.wordpress.org/reference/functions/register_block_type/
39
39
  */
40
- {{#isStaticVariant}}
41
40
  function {{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init() {
41
+ {{#isStaticVariant}}
42
42
  register_block_type( __DIR__ . '/build' );
43
- }
44
- add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' );
45
- {{/isStaticVariant}}
46
- {{#isDynamicVariant}}
47
- function {{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init() {
43
+ {{/isStaticVariant}}
44
+ {{#isDynamicVariant}}
48
45
  register_block_type(
49
46
  __DIR__ . '/build',
50
47
  array(
51
48
  'render_callback' => '{{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback',
52
49
  )
53
50
  );
51
+ {{/isDynamicVariant}}
54
52
  }
55
53
  add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' );
54
+ {{#isDynamicVariant}}
56
55
 
57
56
  /**
58
- * Render callback function
57
+ * Render callback function.
59
58
  *
60
59
  * @param array $attributes The block attributes.
61
60
  * @param string $content The block content.
@@ -63,7 +62,7 @@ add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' );
63
62
  *
64
63
  * @return string The rendered output.
65
64
  */
66
- function {{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback( $atts, $content, $block) {
65
+ function {{namespaceSnakeCase}}_{{slugSnakeCase}}_render_callback( $attributes, $content, $block ) {
67
66
  ob_start();
68
67
  require plugin_dir_path( __FILE__ ) . 'build/template.php';
69
68
  return ob_get_clean();
package/lib/templates.js CHANGED
@@ -111,9 +111,9 @@ const externalTemplateExists = async ( templateName ) => {
111
111
  const configToTemplate = async ( {
112
112
  pluginTemplatesPath,
113
113
  blockTemplatesPath,
114
- defaultValues = {},
115
114
  assetsPath,
116
- variants,
115
+ defaultValues = {},
116
+ variants = {},
117
117
  ...deprecated
118
118
  } ) => {
119
119
  if ( defaultValues === null || typeof defaultValues !== 'object' ) {
@@ -140,9 +140,9 @@ const configToTemplate = async ( {
140
140
  blockOutputTemplates: blockTemplatesPath
141
141
  ? await getOutputTemplates( blockTemplatesPath )
142
142
  : {},
143
- defaultValues,
144
- outputAssets: assetsPath ? await getOutputAssets( assetsPath ) : {},
145
143
  pluginOutputTemplates: await getOutputTemplates( pluginTemplatesPath ),
144
+ outputAssets: assetsPath ? await getOutputAssets( assetsPath ) : {},
145
+ defaultValues,
146
146
  variants,
147
147
  };
148
148
  };
@@ -231,25 +231,14 @@ const getDefaultValues = ( pluginTemplate, variant ) => {
231
231
  editorStyle: 'file:./index.css',
232
232
  style: 'file:./style-index.css',
233
233
  ...pluginTemplate.defaultValues,
234
- ...pluginTemplate.variants[ variant ],
234
+ ...pluginTemplate.variants?.[ variant ],
235
+ variantVars: getVariantVars( pluginTemplate.variants, variant ),
235
236
  };
236
237
  };
237
238
 
238
239
  const getPrompts = ( pluginTemplate, keys, variant ) => {
239
- const defaultValues = getDefaultValues( pluginTemplate );
240
- const variantData = pluginTemplate.variants[ variant ] ?? false;
240
+ const defaultValues = getDefaultValues( pluginTemplate, variant );
241
241
  return keys.map( ( promptName ) => {
242
- if ( promptName === 'variant' ) {
243
- prompts[ promptName ].choices = Object.keys(
244
- pluginTemplate.variants
245
- );
246
- }
247
- if ( variantData && variantData[ promptName ] ) {
248
- return {
249
- ...prompts[ promptName ],
250
- default: variantData[ promptName ],
251
- };
252
- }
253
242
  return {
254
243
  ...prompts[ promptName ],
255
244
  default: defaultValues[ promptName ],
@@ -257,28 +246,21 @@ const getPrompts = ( pluginTemplate, keys, variant ) => {
257
246
  } );
258
247
  };
259
248
 
260
- const getTemplateVariantVars = ( variants, variant ) => {
249
+ const getVariantVars = ( variants, variant ) => {
261
250
  const variantVars = {};
262
- if ( variants ) {
263
- const variantNames = Object.keys( variants );
264
- const chosenVariant = variant ?? variantNames[ 0 ]; // If no variant is passed, use the first in the array as the default
251
+ const variantNames = Object.keys( variants );
252
+ if ( variantNames.length === 0 ) {
253
+ return variantVars;
254
+ }
265
255
 
266
- if ( variantNames.includes( chosenVariant ) ) {
267
- for ( const variantName of variantNames ) {
268
- const key =
269
- variantName.charAt( 0 ).toUpperCase() +
270
- variantName.slice( 1 );
271
- variantVars[ `is${ key }Variant` ] =
272
- chosenVariant === variantName ?? false;
273
- }
274
- } else {
275
- throw new CLIError(
276
- `"${ chosenVariant }" is not a valid variant for this template. Available variants are: ${ variantNames.join(
277
- ', '
278
- ) }`
279
- );
280
- }
256
+ const currentVariant = variant ?? variantNames[ 0 ];
257
+ for ( const variantName of variantNames ) {
258
+ const key =
259
+ variantName.charAt( 0 ).toUpperCase() + variantName.slice( 1 );
260
+ variantVars[ `is${ key }Variant` ] =
261
+ currentVariant === variantName ?? false;
281
262
  }
263
+
282
264
  return variantVars;
283
265
  };
284
266
 
@@ -286,5 +268,4 @@ module.exports = {
286
268
  getPluginTemplate,
287
269
  getDefaultValues,
288
270
  getPrompts,
289
- getTemplateVariantVars,
290
271
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/create-block",
3
- "version": "4.0.1-next.d6164808d3.0",
3
+ "version": "4.1.1",
4
4
  "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -31,7 +31,7 @@
31
31
  "wp-create-block": "./index.js"
32
32
  },
33
33
  "dependencies": {
34
- "@wordpress/lazy-import": "^1.4.3-next.d6164808d3.0",
34
+ "@wordpress/lazy-import": "^1.4.3",
35
35
  "chalk": "^4.0.0",
36
36
  "change-case": "^4.1.2",
37
37
  "check-node-version": "^4.1.0",
@@ -48,5 +48,5 @@
48
48
  "publishConfig": {
49
49
  "access": "public"
50
50
  },
51
- "gitHead": "ba8a396d2f418e53a6c4c50575582f3f3eb11ff7"
51
+ "gitHead": "f6021282457317c7e12dcc3a3f02c9ac28e16a30"
52
52
  }