├── .gitignore
├── README.md
├── bin
└── index.js
├── lib
├── create-acf-block-json.js
├── template-block.json
└── template-php.txt
├── package-lock.json
├── package.json
└── screenshot.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | jspm_packages/
3 | .npm
4 | *.7z
5 | *.dmg
6 | *.gz
7 | *.bz2
8 | *.iso
9 | *.jar
10 | *.rar
11 | *.tar
12 | *.zip
13 | *.tgz
14 | *.log
15 | *.sql
16 | .DS_Store*
17 | ehthumbs.db
18 | Icon?
19 | Thumbs.db
20 | ._*
21 | *.un~
22 | .sass-cache
23 | .lando.local.yml
24 | .env
25 | .env.development.local
26 | .env.test.local
27 | .env.production.local
28 | .env.local
29 | docker-compose.override.yml
30 | .cache
31 | logs
32 | *.log
33 | npm-debug.log*
34 | yarn-debug.log*
35 | yarn-error.log*
36 | lerna-debug.log*
37 | .pnpm-debug.log*
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Create ACF Block JSON
2 |
3 | > Quickly create a new [WordPress](https://wordpress.org) Block that uses [Advanced Custom Fields](https://www.advancedcustomfields.com) (ACF) and utilises block.json and block-specific CSS and PHP files.
4 |
5 | If you use ACF and make Gutenberg blocks, this simple utility should save you time scaffolding custom blocks.
6 |
7 |
8 |
9 | ## Quick Start
10 |
11 | Install globally via npm:
12 |
13 | ```sh
14 | npm install --global create-acf-block-json
15 | ```
16 |
17 | then navigate to where you want your block to be (i.e. /theme/blocks/), and run:
18 |
19 | ```
20 | $ create-acf-block-json
21 | ```
22 |
23 | ## What does Create ACF Block JSON do
24 |
25 | Create ACF Block JSON is an npm package command line program that will create a new folder in your current directory containing scaffolding for a new WordPress block using Advanced Custom Fields.
26 |
27 | It will generate:
28 |
29 | - Folder - containing folder for your block.
30 | - block.json - prefilled with common block information and default values.
31 | - PHP file - setup with basic information, classes and innerblocks.
32 | - SCSS files - for the frontend and editor. SCSS is useful if you use a compiler to output CSS files.
33 | - CSS file - for the frontend and editor. To write straight CSS or be overwritten by your processed SCSS.
34 |
35 | The script handles generating a unique class (.wp-block-namespace-name) for your block which is then referenced in each file.
36 |
37 | This script doesn't handle registration of the block - we recommend directory scanning methods to auto load blocks without registering each one. This method is outlined by [Bill Erickson](https://www.billerickson.net/building-acf-blocks-with-block-json/#advanced-usage), but there are [other examples](https://github.com/cncf/cncf.io/blob/0233ccfa1fb24d46ce119049b010a18a0e3d91d3/web/wp-content/themes/cncf-twenty-two/includes/acf.php#L19) online. This blog post by ACF also talks about how to register an ACF block, [follow this guide](https://www.advancedcustomfields.com/resources/how-to-upgrade-a-legacy-block-to-block-json-with-acf-6/). FYI, many guides are out of date, make sure you use guides released after 28th September 2022 (when ACF 6.0 was released) which will properly use block.json. If you want a very quick bit of PHP to register your new block, you can use this:
38 |
39 | ```
40 | /**
41 | * Load My Create ACF Block JSON Blocks
42 | */
43 | function thetwopct_load_acf_blocks() {
44 | register_block_type( get_template_directory() . '/blocks/my-acf-block/block.json' );
45 | // register_block_type( get_template_directory() . '/blocks/another-block/block.json' );
46 | }
47 | add_action( 'init', 'thetwopct_load_acf_blocks' );
48 | ````
49 |
50 | ## Customisation Options
51 |
52 | When you run `create-acf-block-json` you are asked a few questions before your block is created:
53 |
54 | - Namespace: Specify a namespace for the block (defaults to `acf`)
55 | - Name: Give your block a name, i.e. "My Cool Block" (required)
56 | - Description: Describe the functionality of your block so editors and users can find it easily (optional)
57 | - Icon: The icon for your block - use any [Dashicons](https://developer.wordpress.org/resource/dashicons/) name (defaults to icon `star-filled`). Note, when copying the name of the Dashicon you must remove the prefix `dashicons-`, for example: `dashicons-smiley` should be written as `smiley`.
58 |
59 | The script will then generate all required files. From there, you can edit, delete, remove the files as you wish.
60 |
61 | ## Install Create ACF Block
62 |
63 | 1. Using terminal or another CLI, download from npm and install as a global package - `npm install -g create-acf-block-json`
64 | 2. Using terminal or another CLI, navigate to your WordPress theme folder where you want all of your blocks (we use /wp-content/themes/my-theme/blocks/)
65 | 3. Run `create-acf-block-json` and follow prompts.
66 |
67 | ## Update Create ACF Block
68 |
69 | To update to the latest version you can just run the install command again - `npm install -g create-acf-block-json`
70 |
71 | ## Feedback and issues
72 |
73 | Please open an issue in the [GitHub repo](https://github.com/thetwopct/create-acf-block-json/issues). Thanks.
74 |
--------------------------------------------------------------------------------
/bin/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const create = require("../lib/create-acf-block-json");
4 |
5 | create.acfBlock();
6 |
--------------------------------------------------------------------------------
/lib/create-acf-block-json.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const prompts = require('prompts');
3 |
4 | const DIR = '.';
5 |
6 | const QUESTIONS = [{
7 | type: 'text',
8 | name: 'namespace',
9 | message: 'Block Namespace',
10 | initial: 'acf'
11 | },
12 | {
13 | type: 'text',
14 | name: 'title',
15 | message: 'Block Name'
16 | },
17 | {
18 | type: 'text',
19 | name: 'description',
20 | message: 'Block description',
21 | initial: ''
22 | },
23 | {
24 | type: 'text',
25 | name: 'icon',
26 | message: 'Dashicon',
27 | initial: 'star-filled'
28 | }
29 | ];
30 |
31 | exports.acfBlock = function() {
32 |
33 | console.clear();
34 | console.log('Create ACF Block JSON is running...');
35 | console.log('');
36 | console.log('This will create a new folder in the current directory containing scaffolding for a new WordPress block using Advanced Custom Fields.');
37 | console.log('');
38 |
39 | let cancelled = false;
40 |
41 | // Listen for SIGINT signals and set the "cancelled" flag to true.
42 | process.on('SIGINT', () => {
43 | console.log('Cancelled.');
44 | cancelled = true;
45 | });
46 |
47 | // Helper function for creating files.
48 | const createFile = async (path, content, successMessage, errorMessage) => {
49 | try {
50 | fs.writeFileSync(path, content);
51 | console.log(successMessage);
52 | } catch (error) {
53 | console.error(errorMessage, error);
54 | }
55 | };
56 |
57 | (async () => {
58 | const response = await prompts(QUESTIONS, {onCancel: () => {cancelled = true}});
59 |
60 | // Check if the user cancelled the prompts.
61 | if (cancelled) {
62 | console.log('Aborting...');
63 | return;
64 | }
65 |
66 | const title = response.title;
67 | const slug = response.title.replace(/\s+/g, '-').toLowerCase();
68 | const namespace = response.namespace.replace(/\s+/g, '-').toLowerCase();
69 | const qualifiedName = namespace + '/' + slug;
70 | const folder = '/' + slug;
71 | const absolute = DIR + folder;
72 |
73 | // Create default CSS class.
74 | const css = '.wp-block-' + namespace + '-' + slug + ' {}';
75 |
76 | // Create Folder.
77 | if (!fs.existsSync(absolute)) {
78 | fs.mkdirSync(absolute);
79 | } else {
80 | console.log('Error: A directory called ' + slug + ' was already found. Aborting.')
81 | return;
82 | }
83 |
84 | // Handle cancellation.
85 | if (cancelled) {
86 | console.log('Aborting.');
87 | return;
88 | }
89 |
90 | // Create files.
91 | await createFile(
92 | absolute + '/' + slug + '.css',
93 | `/* ${css} */`,
94 | `${slug}.css created`,
95 | 'Error creating CSS file:'
96 | );
97 | await createFile(
98 | absolute + '/' + slug + '.scss',
99 | `// ${css}`,
100 | `${slug}.scss created`,
101 | 'Error creating SCSS file:'
102 | );
103 | await createFile(
104 | absolute + '/editor.css',
105 | `/* ${css} */`,
106 | `editor.css created`,
107 | 'Error creating editor CSS file:'
108 | );
109 | await createFile(
110 | absolute + '/editor.scss',
111 | `// ${css}`,
112 | `editor.scss created`,
113 | 'Error creating editor SCSS file:'
114 | );
115 |
116 | // Handle cancellation.
117 | if (cancelled) {
118 | console.log('Aborting.');
119 | return;
120 | }
121 |
122 | // Get the PHP template and turn in to PHP.
123 | let phpTemplate = '/template-php.txt';
124 | try {
125 | let data = fs.readFileSync(__dirname + phpTemplate, 'utf8');
126 | data = data.replace(/XYZ/g, title)
127 | .replace(/QWY/g, slug)
128 | .replace(/DX9S/g, namespace)
129 | .replace(/\r\n/g, '\n');
130 | await createFile(
131 | absolute + '/' + slug + '.php',
132 | data,
133 | `${slug}.php created`,
134 | 'Error creating PHP template:'
135 | );
136 | } catch (error) {
137 | console.error('Error creating PHP template:', error);
138 | }
139 |
140 | // Handle cancellation.
141 | if (cancelled) {
142 | console.log('Aborting.');
143 | return;
144 | }
145 |
146 | // Get the Block.json template.
147 | let jsonTemplate = '/template-block.json';
148 | try {
149 | let raw = fs.readFileSync(__dirname + jsonTemplate);
150 | let template = JSON.parse(raw);
151 | // Update Block.json values.
152 | template.name = qualifiedName;
153 | template.title = title;
154 | template.description = response.description;
155 | template.icon = response.icon;
156 | template.style = 'file:./' + slug + '.css';
157 | template.editorStyle = 'file:./editor.css';
158 | template.acf.renderTemplate = slug + '.php';
159 | let jsonContent = JSON.stringify(template, null, "\t");
160 | await createFile(
161 | absolute + '/block.json',
162 | jsonContent,
163 | 'block.json created',
164 | 'Error creating JSON template:'
165 | );
166 | } catch (error) {
167 | console.error('Error creating JSON template:', error);
168 | }
169 |
170 | })();
171 | }
172 |
--------------------------------------------------------------------------------
/lib/template-block.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schemas.wp.org/trunk/block.json",
3 | "apiVersion": 3,
4 | "name": "",
5 | "title": "",
6 | "description": "",
7 | "style": "",
8 | "editorStyle": "",
9 | "editorScript": [],
10 | "category": "common",
11 | "icon": "awards",
12 | "keywords": [
13 | "",
14 | "",
15 | ""
16 | ],
17 | "acf": {
18 | "mode": "preview",
19 | "renderTemplate": ""
20 | },
21 | "supports": {
22 | "mode": false,
23 | "align": [
24 | "wide",
25 | "full",
26 | "left",
27 | "center",
28 | "right"
29 | ],
30 | "alignWide": true,
31 | "alignContent": false,
32 | "alignText": false,
33 | "anchor": true,
34 | "className": true,
35 | "color": {
36 | "background": false,
37 | "gradients": false,
38 | "link": false,
39 | "text": false,
40 | "enableContrastChecker": false
41 | },
42 | "customClassName": false,
43 | "defaultStylePicker": true,
44 | "html": false,
45 | "multiple": true,
46 | "reusable": true,
47 | "spacing": {
48 | "margin": false,
49 | "padding": false
50 | },
51 | "typography": {
52 | "fontSize": false,
53 | "lineHeight": false
54 | }
55 | },
56 | "attributes": {
57 | "variable": {
58 | "type": "string",
59 | "default": ""
60 | }
61 | },
62 | "example": {}
63 | }
--------------------------------------------------------------------------------
/lib/template-php.txt:
--------------------------------------------------------------------------------
1 |
44 |
45 |
Open the blocks PHP file to edit this text.
48 | '; 50 | ?> 51 |