Native Gutenberg Blocks Without React: FanCoolo WP Tutorial
FanCoolo WP lets you create native Gutenberg blocks without React or build tools. You write PHP, SCSS and JS inside your WordPress dashboard, and your blocks get native sidebar controls with nothing to compile. In this video we build a block from scratch and show the full workflow: settings, the Monaco editor, hot reload, attributes, reusable Symbols, SCSS Partials and what happens when you break your PHP.
Plugin introduction
The blocks FanCoolo WP creates are real Gutenberg blocks, so their settings use native Gutenberg fields in the block sidebar. You write your markup in PHP instead of React, so nothing needs to be compiled and you can work safely on your server.
On top of that you get:
- Symbols: reusable components that you can use to build a full design system
- SCSS Partials: compiled in the browser, so you can split your styles into functions and smaller files
- Hot reload, revisions and InnerBlocks support
- A Monaco editor with Emmet autocomplete, so it feels like you never left VS Code
- Error messages that tell you where the problem is, while your visitors keep seeing the last working version of the block
Configuration types: Blocks, Symbols and SCSS Partials
Once you add your license and click Add new, the Component Type screen gives you three options:
- Blocks: the core of the plugin. These are the Gutenberg blocks you create.
- Symbols: reusable PHP components you add to blocks, for example one button used across many blocks.
- SCSS Partials: reusable styling fragments, so your CSS is split into smaller pieces that are easier to write.
Creating your first block
- Choose Blocks, enter a Block Title (we used "Hello") and click Create.
- In the right sidebar, open Settings. Under Block Configuration you can set a Description, pick a Category (for example Text) and choose an Icon.
- Under Inner Blocks Settings, turn on Enable Inner Blocks if the block should hold other blocks. You can then set which blocks are allowed and which are added by default, like a paragraph, heading, image or one of your own custom blocks.
- Under View.js Settings, Enable Module switches view.js to ES module format (viewScriptModule). Use it for the WordPress Interactivity API. WordPress then loads the script in the header. If you want plain JS in the footer, leave it off (the default).
- Dangerous area → Delete Permanently deletes the block.
The editor has five tabs: Content, Style, Editor Style, View and Attributes. A new block starts with a wrapper in Content:
<div <?php echo get_block_wrapper_attributes(); ?>>
<!-- Your code goes here -->
</div>
Type h1 and Emmet autocomplete expands it right away. Add "Hello", save, then insert the block on a page. You'll see the same content in the editor and on the front end.
Monaco editor and hot reload
FanCoolo generates the block class for you: wp-block-, then the namespace, then the block name. In the Style tab you get CSS autocomplete, and you press Tab to accept a suggestion:
.wp-block-fancoolo-hello {
background-color: lime;
}
Save, and the open front-end page updates without a manual refresh. Change the color to red and it turns red, and text changes show up the same way. If you have two screens, detach the front-end window and hot reload still works.
Attributes and revisions
Before making the block dynamic, open Revisions in the sidebar. Enter a title under Create Revision (we used "Base") and click Save Revision. It then appears under Revision History next to Current, so you can go back to the static version later.
Next, add a title attribute in the Attributes tab, save, and use it in Content:
<div <?php echo get_block_wrapper_attributes(); ?>>
<?php if (!empty($attributes['title'])): ?>
<h1><?php echo esc_html($attributes['title']); ?></h1>
<?php endif; ?>
<button>Click me</button>
</div>
The block now has a title field. We typed "This is an awesome title". Then we gave the button a cta class. The Style tab is SCSS by default, so you can nest the button styles right inside the block's selector:
.wp-block-fancoolo-hello {
background-color: lime;
.cta {
/* your button styles */
}
}
Reusable Symbols
You don't want to write the same button in every block, so turn it into a Symbol:
- Click Add new, choose Symbols and name it "Button".
- Paste the button markup into the Symbol and save.
- In the block's Content, replace the button with a reference to the Symbol:
<Button />. - Save and reload. The block now renders the Symbol.
To change the text for each use, read a value from $symbol_attrs and set a fallback:
<?php
$text = $symbol_attrs['text'] ?? 'Button text';
?>
<button class="cta"><?php echo esc_html($text); ?></button>
With no override the button shows "Button text". Override it in the block like this:
<Button text="Click me" />
This lets you reuse one set of styles and still say "Read me" in one card and "Read more" in a post loop. The FanCoolo documentation has more examples of multiple overrides, including button variations, sizes, links and true/false values:
<!-- Large Primary Button -->
<Button text="Get Started" type="primary" size="large" />
<!-- Link Button -->
<Button text="Read More" type="primary" url="/about" />
<!-- Disabled Button -->
<Button text="Unavailable" disabled="true" />
SCSS Partials and globals
Next we moved the button styles out of the block and into a partial:
- Click Add new, choose SCSS Partials and name it "button".
- Paste the
.ctastyles and save. - Remove them from the block's Style tab and save. After a reload the button has no styles.
- In the block sidebar, open the SCSS Partials tab and include the "button" partial. The styles come back.
.cta {
background-color: orange;
color: black;
padding: 1rem 2rem;
border-radius: 1000px;
border: 0;
}
For functions, color variables or breakpoint helpers that every block needs, open the partial's Settings and turn on Include in all blocks under Global SCSS Partials. Load Order controls the sequence (lower numbers load first). Functions add no weight to your CSS until you use them.
Error handling
You can build blocks locally or edit them directly on the server, because broken code never ships. If you break the PHP (we removed the ? from the closing ?> on line 1), saving shows an error with the line number. Until you fix it, FanCoolo doesn't overwrite the block file and keeps serving the last working version. Only the person editing sees the error. Visitors never see a broken block.
FAQ
Do I need React or npm to create Gutenberg blocks with FanCoolo WP? No. You write the block markup in PHP and the styles in SCSS inside the WordPress dashboard. Nothing needs to be compiled and there is no build step.
Are these real Gutenberg blocks?
Yes. FanCoolo creates native blocks that use Gutenberg's own sidebar fields. The front-end wrapper comes from get_block_wrapper_attributes(), and each block gets a wp-block- class with the namespace and block name.
What is the difference between a Symbol and an SCSS Partial?
A Symbol is a reusable PHP component, such as a button, that you reference in a block as <Button /> and can override per use. An SCSS Partial is a reusable piece of styles that you include in specific blocks or load globally with Include in all blocks.
What happens if I save a block with a PHP error? You get an error message with the line number, and the block file isn't replaced. Visitors keep seeing the last working version until you fix the error.
Can I use the WordPress Interactivity API? Yes. Turn on Enable Module under View.js Settings to load view.js as an ES module (viewScriptModule). Leave it off for a classic script in the footer.
Get FanCoolo WP → dplugins.com