Closed brentvr closed 5 years ago
So our main question here seems to be:
Do we want to isolate Gutenberg in something like the /assets/admin
directory we have now or restructure with a component-based architecture and try to integrate blocks.
I can see costs/benefits to both. I like the idea of a component architecture, but it certainly isn't without its challenges.
Hey all.
Chatted to a few folks about a potential structure here.
Hard to convey what I'm proposing, so I'll try and build it up from our normal scaffolding structure to what it w/could look like with gutenberg blocks.
theme
/ assets
/ gulp-tasks
/ includes
/ partials
archive.php
page.php
theme
/ assets
/ includes
/ gutenberg
/ blocks
- all-gutenberg-blocks.css
/ author-card
/ hero-area
/ recommended-posts
theme
/ assets
/ includes
/ gutenberg
/ blocks
- all-gutenberg-blocks.css
/ author-card
— author-card.php
— author-card-admin.js
— author-card-fe.js
— author-card.css (styles for FE and admin)
The author-card block has 3 essential files: a PHP file, a JS and a CSS file. It can have more of each, and it's own folder sub-structure, but that's the minimum required to make a block work.
The first two files are self-explanatory and uncontentious — they're basic gutenberg files. This is where you'll register the block, do all the actual block-building, etc.
/ author-card
— author-card.php
— author-card-admin.js
The other two are worth a closer look:
/ author-card
— author-card-fe.js (if this block requires any frontend JS )
— author-card.css (one set of styles for the frontend and admin)
That's the goal coming out of the few discussions I've had with people, at least until we learn that that's not a good idea for some reason.
The file all-gutenberg-blocks.css
becomes a manifest for all of the blocks' styles:
/ gutenberg
/ blocks
- all-gutenberg-blocks.css
import author-card.css
import hero-area.css
import recommended-posts.css
import etc
This all-gutenberg-blocks.css
can be imported to the main frontend stylesheet and to the main admin stylesheet.
That was probably all a bit abstract. If you've worked with Gutenberg before on a project or are just diving in now, I'd appreciate any feedback you have. It's definitely possible that we're missing a use-case that would make some of what I've described impossible.
Hit me up in Slack if you'd rather have a chat about this potential structure than reply here.
Thanks all!
I don't think we should be shy about blowing up the current scaffold structure if we have a better implementation (that's part of the reason it isn't hidden in a generator now). I'm definitely not a fan of stuff in the includes directory. I've been kicking around something like this:
<root>/src/
components/
component-name/
component-name.css
component-name.js
fonts/
images/
admin/
gutenberg-blocks/
block-name/
block-name.js (for the block)
block-name.css (for the block, include site-level with @import if you need it)
block-name.php
icons/
utilities/
utility-name/ (maybe, “base”, “typography”, “debounce”, etc.)
utility-name.css
utility-name.js
frontend.js
frontend.css
index.js (site entry point)
gutenberg.js (guten-entry point)
admin.js (general admin point)
Should we keep this issue only related to custom blocks? There are many areas how you add theme support for the editor (wide, full width etc.), how to style Core blocks etc.
Having the js/css in the /includes/ folder is as strange as having php in the /src/ folder, I think.
There will be weirdness either way. Includes now has content types, functions, template tags, classes, etc. I don't think gutenberg blocks are out of place there.
We'll agree to disagree on src vs includes, but for me, the primary thing is not fragmenting the UI code. Our first duty on projects is to create a good public-facing website, so the structure shouldn't have to bend to that by adding front-end UI code into a /gutenberg
directory (author-card-fe.js
<- we also shouldn't rely on file naming like that). If you need to update a UI card (for example) you wouldn't go into the Gutenberg directory, that wouldn't make any sense and new people rolling onto a project would never find it. The UI code should be where it needs to be and it Gutenberg needs it, it can be pulled in from the original location.
I'd also consider building custom blocks in it's own custom plugin. Not in theme-scaffold, or in plugin-scaffold.
I want to echo what @samikeijonen brought up here https://github.com/10up/theme-scaffold/issues/78#issuecomment-431258593 and https://github.com/10up/theme-scaffold/issues/78#issuecomment-431562539.
I think we need to take few steps back here. The initial phase for Gutenberg that will be merged into Core is limited to only the content area (post_content) for posts and pages. Gutenberg may grow beyond content area in the future, and only then we should consider completely restructuring the Scaffold architecture.
For now, to be ready for 5.0 release, I think we need to do two things. 1) Make the Scaffold Gutenberg ready like @samikeijonen suggested. Just like https://github.com/10up/theme-scaffold/blob/master/assets/css/frontend/base/wordpress.css, we should include block.css and include baseline styles like alignwide or alignfull etc (https://github.com/WordPress/gutenberg-starter-theme/blob/master/css/blocks.css) which will be generated from Core blocks that all projects will need. There might be some additional things we might need to do to be Gutenberg ready. 2) Second problem we should address is how to incorporate Custom Blocks into our projects. I don't have any experience developing with Gutenberg yet but based on my research, I agree with @samikeijonen and should consider it being a separate plugin and not within theme-scaffold or in plugin-scaffold.
Break this issue into two separate issues? One to make Scaffold Gutenberg ready and one for Custom Block development?
To Tim's point here https://github.com/10up/theme-scaffold/issues/78#issuecomment-431368084
The UI code should be where it needs to be and it Gutenberg needs it, it can be pulled in from the original location.
The proposed structure here was the result of a several conversations with people suggesting that keeping everything together was advantageous. This way we could, theoretically, easily share / reuse blocks among projects and in a directory of blocks, if such a thing existed.
We're talking about (potentially) 4 files: admin PHP, admin JS, frontend JS, block.css in 3 different places.
Again, no particular horse in the race, but the keep-everything-together conversations were what led to this proposed structure.
To Sang and Sami's point about theme vs custom plugin:
My thoughts are:
Would love to hear from @simondowdles @ivanlopez @brentvr and anyone else who's gone through a project with Gutenberg so far.
Following the principles of the Plugin Territory discussion, custom blocks in theory should live within a custom plugin. Changing themes should not break any existing content (having custom blocks in a theme would break it).
I'm not saying necessarily that we must write custom blocks on plugins for all projects but naturally Custom Blocks should be on plugins and the theme should only provide support for those blocks by adding styles for it.
I'm sort of in agreement with @samikeijonen and @nicholasio here. There's a slightly confusing overlap between the responsibilities of a theme and plugin in the Gutenberg world. Ideally, a plugin would be responsible for the admin UI and data structure of a custom Gutenberg block, and a theme would be responsible for the public UI and functionality of said block.
Perhaps a best of both worlds can be reached by ensuring that themes are able to override a default rendering of custom blocks.
I definitely agree that the theme should be responsible for the styling of all built-in blocks. I think they will fit into our current paradigm quite well, as their styling can go into the assets/css/frontend/components/
directory. As far as the browser is concerned, they're really no different to any other BEM block.
Reading all of the above leaves me somewhat on the fence, as both sides of the coin have valid arguments. Having built a site that consists of a fair amount of Gutenberg blocks, and having felt that tangible bit of Gutenberg, I am leaning more toward the side of not having blocks be plugin based, for a couple of reasons (and I encourage healthy debate):
Blocks replace the editing experience, and thus the manner in which the post content is produced. Post content === presentation layer of the site === theme (in my opinion). We've never resorted to plugins for regular content display, so what makes blocks an exception?
In my experience - and unless we're offering some form of 10up block library that developers could use if they wanted to - blocks are most of the time specific to the build and even more specific to the layout of the website, i.e they are quite theme reliant in terms of where they appear and how they appear in the content. Bundling the blocks within the theme makes it far easier to control the build process, asset inclusion (i.e compiling into same theme assets) etc.
If multiple blocks are created as multiple plugins (or even one plugin), every time said block is used in the theme, there will need be a series of checks (maybe 1, maybe more) to ascertain whether that block partial truly is available to us. This may be as simple as defining a constant for each block that exists, or checking the partial path within the plugin folder, but nonetheless it's still a check that needs to be done each and every place the block is called. This can be error prone, although is a minor point.
I'm working on a project at the moment that has multiple components (17 at the moment) and almost all of these components need to be able to used inside of a Gutenberg context (i.e author places block) AND outside of a Gutenberg context, i.e theme developer needs to hard include the component partial in specific templates. If the Gutenberg blocks are bundled within the theme, this makes the process far more trivial, easier to control from an asset perspective and just more logical IMO.
While this may differ from build to build, every time you want to test a presentation layout relating to block usage within a theme, imagine having to recompile and redeploy both plugin(s) and theme code and build each separately, possibly managing deploys or plugin updates each time you wanted to go to stage or develop environments? Might seem nit picky, but it seems as though it would be easier to manage this via one source, i.e theme.
If a theme needs to override how a block looks or functions, it's likely going to do that via an includes
or a src
folder anyway, and place the block library therein. We then have 2x locations of block PHP, JS and CSS, and when blocks become more complex, it may inevitably lead to confusion or at the very least increase the opportunity for error (i.e developer X changes plugin instead of theme override)
I am sure there will be counter arguments around block libraries (if 10up has plans to offer a library) and how we share those, but how I imagine those being managed are simply as a component library in a repo, and affording the engineer(s) the ability to include those blocks how they see fit in the theme (or a plugin if they choose), and in a manner that works best for the project.
Then there is the very legitimate argument that @nicholasio gave around changing a theme not resulting in broken content, which is a very fair argument indeed. The blocks are mostly going to be theme dependent anyway, and if we stick to a simple single-folder-for-components approach, it's as quick and easy to port those to a new theme than it is to install plugins. I do believe though that most custom blocks made for a specific project (and thus theme) would almost always be out of place in a different theme anyway. That may be a dangerous assumption to make though...
I'm all for a scaffold aiding in a best practice first step, but I think we need to be careful about dictating a plugin vs. theme usage. That should be project dependent.
In terms of structure, I as an engineer am not particularly phased whether it is in src, includes or components, as long as the structure is a) obvious and b) sensible.
This is merely an opinion. Please challenge it.
While I did not yet have time to review the entire thread (will on Wednesday), here are some key items we should keep in mind:
Apologies if this has already been said but considering we're just not sure how Gutenberg is going to be used by the engineers who want to use this scaffold, perhaps we should start by simply setting up for its use with the appropriate package.json, eslint set up etc.
https://github.com/10up/eslint-config/issues/6 @ryanwelcher there's a related discussion going on about that there ^
Doesn't mention gutenberg, but we've been chatting about how that will impact Gutenberg / React / whatever
I personally feel the block should live where the feature lives. So for example, if a block allows you to display content related to a CPT and the CPT lives within the theme then the blocks should live within the theme or if we have a plugin that lets you do something with Google Maps then the blocks related to that should live within that plugin. I think each project is a little different and having the flexibility to easily add Gutenberg blocks to a theme or plugin in a standard way is important. Agreeing on a folder structure across the board will make it that much easier as new engineers onboard onto projects.
I am also in favor of not putting the Gutenberg blocks in the Theme directly. Apart from the Theme activation issues, there are also uses cases like Multi-site/Distributor where the FE may be absent and there is no active theme. Placing the Gutenberg block code within a feature/mu-plugin plugin seems a safer approach.
On a recent project the approach that I went with was,
MU-Plugin:
1) Update package.json with Gutenberg dependencies
2) Add Gutenberg components under assets/js/blocks in separate JS files.
3) Include each component into an editor.js
with import ./blocks/foo.js
4) Build pipeline updated to output an editor.js
that is enqueued on Post edit screens.
5) Block is registered in PHP and renders as get_template_part/partial( 'blocks/{name}', $opts )
Theme: 1) blocks/{name}.php - Markup for the block 2) CSS is modularized in the same format we already do under assets/css/frontend/components.
This worked well for the BE & FE collaboration. FEE created static page templates and added CSS that BEE wired using data inside the Block. ie:- More or less the same workflow as we currently follow.
This provides the separation so that the Admin experience is provided by the Plugin & the custom block markup and CSS comes from the Theme. The one caveat is that I'm only building Dynamic blocks at the moment. They are easier to divide in this manner.
We are not suggesting that you only ever build blocks in themes here. Only to include support in the theme scaffold for building project specific custom blocks in a standardised way. A way in which the core block code is contained in a block folder but can still leverage functionality from that theme code.
@dsawardekar for the example you mention with Multi-site/Distributor, it would make sense to use an mu-plugin or a parent theme could even be leveraged. I would definitely support the approach of using a mu-plugin if that was where most of the site functionality exists. Using a standard plugin can involve more maintenance and can still result in broken content when deactivating the plugin.
I think it would be fair to say that if we had to switch out a theme on the majority of sites we build, we'd need to revise the appearance of content. If a theme was to change, it would involve a thought out plan and as Simon mentioned, if we had a consistent approach to building blocks in a theme it would make it more straightforward to port the code over to the new theme.
As Ivan points out, blocks should exist where the supporting data structures and functionality being leveraged for the feature exist. I imagine we'll be building blocks which will be needing to heavily integrate with the functionality laid out in the theme. For example pulling dynamic content from specific custom post types and taxonomies, using theme partials, caching and helper functions.
If we've got at least some agreement that blocks will live in the theme at least some of the time, should we move forward with adding blocks to the theme setup?
I have not developed anything Gutenberg yet. 😉
I would love to see a separate repo(s) of 10up Gutenberg Custom Blocks (published as npm
packages), as well as a corresponding 10up plugin (e.g. 10up Gutenberg Blocks Scaffold) that one can pull in the 10up Gutenberg Custom Blocks in to. The 10up Gutenberg Blocks Scaffold plugin would include all the tooling to generate a new block, as well as allow theme's to override existing blocks. Perhaps, allowing theme to do something like:
add_theme_support( 'tenup_blocks', array(
'blocks' => array(
'block1',
'block2',
)
);
The idea being that initially (and most generally) the 10up Gutenberg Blocks Scaffold would be added to a Gutenberg project. Should a client's site require a custom WP installation configuration then elevating the 10up Gutenberg Blocks Scaffold plugin to be a mu-plugin
would be trivial. Should a custom 10up Gutenberg npm packaged block be needed on a project. It would first be added to the 10up Gutenberg Blocks Scaffold. Should further customization be needed then either the package is migrated to the theme, or just certain assets are overridden with path matching. E.g. /plugins/tenup-gutenberg-blocks-scaffold/components/custom-block-1/custom-block-1.css
gets moved to /themes/tenup-theme/components/custom-block-1/custom-block-1.css
Also, the 10up Gutenberg Blocks Scaffold would have a general styles.css
that sets general styles for out-of-box Gutenberg components. With tooling to update the styles.css
per project.
🤔 Pie in the sky idea?
I've got some free time this week, so I'm starting an initial run at this.
My vague plan is as follows:
Though that order might well move around!
@brentvr should we retitle this Issue to prefix the word "Custom..."? I think it mainly revolves around developing Custom Blocks for Gutenberg.
Whereas, I think a separate Issue and discussion need to be started in regards to how/if we want to use any of Gutenberg's add_theme_support()
options, or leverage any of the new enqueueing hooks it introduces: "Gutenberg Handbook: Theme Support"
During the State of the Word Q&A few hours ago, Matt Mullenweg said "Any blocks being registered be in a plugin and please don't do that in themes". I believe he said that this is also a guideline (but I don't think this is official). He went on to say that he envisions/would like to see a "block" directory just like a plugin directory. I think this sorta gives us a clear direction to move forward with this issue. Maybe move forward with what several of us mentioned on this thread and I sorta summarized here: https://github.com/10up/theme-scaffold/issues/78#issuecomment-431709100? 1) Make 10up Scaffold Gutenberg ready 2) For how to incorporate Custom Blocks into our projects, maybe we create a 3rd scaffold for blocks in addition to theme and plugin as @samikeijonen mentioned (https://github.com/10up/theme-scaffold/issues/78#issuecomment-431562539)?
I've opened a PR for a very much in-progress PR for adding Gutenberg block support to the theme-scaffold. Please feel free to peruse: https://github.com/10up/theme-scaffold/pull/96
Hi everyone, kind of reviving this thread. Sorry if I'm doing it wrong or if I'm missing the point of this discussion... there's a lot to digest :)
Currently, we're keeping PHP / JS / CSS separated so I'm not sure why they should be in the same folder for Gutenberg blocks, I feel like sharing blocks on projects will be pretty rare and even if they are shared, the styles probably won't, so there's no need to put everything in the same folder?
| - assets/
| | - css/
| | | - admin/
| | | | - example-block-1.css (Optional, if block editor styles differ)
| | | | - example-block-2.css (Optional, if block editor styles differ)
| | | | - example-block-3.css (Optional, if block editor styles differ)
| | | - frontend/
| | | - gutenberg/
| | | | - example-block-1.css
| | | | - example-block-2.css
| | | | - example-block-3.css
| | | - shared/
| | | - styleguide/
| | - js/
| | | - admin/
| | | - frontend/
| | | - gutenberg/
| | | | - example-block-1.js (optional, block may not need front-end facing JS)
| | | | - example-block-2.js (optional, block may not need front-end facing JS)
| | | | - example-block-3.js (optional, block may not need front-end facing JS)
| | | - shared/
| - includes/
| | - gutenberg/
| | | - example-block-1/
| | | | - example-block-1.js
| | | | - example-block-1.php
| | | - example-block-2/
| | | - example-block-3/
The CSS partials can be imported/shared in whichever stylesheet they're needed (admin, editor, frontend), and enqueued as usual. Right now, I don't think Gutenberg selectively loads CSS on a page depending on block usage so I don't see the point in having the CSS individually enqueued per block.
| - example-block/
| | - PHP
| | - JS
| | - CSS (admin-facing, "standalone")
with the front-end facing CSS partial still in the theme, since we will need to customize it to match a site's design anyway.
Hope this makes sense!
@kdo I'm totally fine with that structure. Can you open a PR so we can get this moving. To me this is a priority.
Hi @saltcod @timwright12 would appreciate if you could sanity-check #112 !
PR looks great @kdo! Left one comment about needing wordpress/default in the .babelrc. I'm not sure if it's necessary tbh.
As for location of this structure — we put it in a mu-plugin last time around with a bunch of other functionality. On our most recent project, we don't have nor need a mu-plugin for anything else, so it made sense to keep everything simple and housed in the same theme dir.
Where to put Gutenberg files will always be a project-level decision, but in-the-theme is definitely going to be one of the options.
@kdo I'm in a build now and am finding that keeping all Gutenberg things together is making a lot of sense to me. One thing we're not taking into account is non-block items, for example, the project I am on has blocks and custom UI elements such as filters and slotfiils.
Our structure looks like this:
| - includes
| -- gutenberg
| --blocks
| --{block-name}
| --block-name.js
| --block-name.php
| --{custom-ui-feature-name}
I think that adding a block-name.css
where the other block assets are stored makes sense from a code organization point of view. Also, depending on the project we might be pulling the CSS into the JS and this approach would make that easier.
There is an argument that block CSS is really part of the FE and should be stored in assets accordingly. I agree with that for the most part however core provides three hooks for GB that allows us to enqueue CSS/JS for blocks on the FE, BE and both and as we move forward with more complex blocks. I can see a need to have a CSS file for each of those cases, at which point having everything together becomes a much better solution.
Recently merged v1 of this, closing it out
With WordPress 5.0 set for release, we should begin preparation for updating the scaffold to include support for Gutenberg block development within themes.
I'm proposing that we introduce a folder at the root of the theme, which would contain a list of block folders. Each block folder would contain all code pertaining to that block including PHP, JS and CSS.
Optionally, other components can live in the components/ folder, which can contain all reusable custom components which are included in the block JS.
The block JS code can be enqueued using: