flyntwp / flynt-core

The core building block of the Flynt Framework.
MIT License
12 stars 0 forks source link

Component file structure. #48

Open fabianmarz opened 5 years ago

fabianmarz commented 5 years ago

As far as I can see from the code, Flynt is currently not capable of having nested/grouped components. This can get confusing for bigger projects, especially if you want to create a set of shared components (which seems also not possible currently).

For shared components we currently using this workaround to register a twig namespace and reference it in a sibling template. How do you at bleech realise shared components currently? E.g. have a teaser article shown in a grid and in a listing.

add_filter('timber/loader/loader', function($loader) {
  $loader->addPath(Feature::getOption('flynt-components', 0), 'Component');
  return $loader;
});
{{ include '@Component/BlockButton/index.twig' }}

To have it more structured we thought it would be helpful to have a grouped folder structure like this:

Components
  Block
    Button
    Image
  List
    Posts
    Users   

Then add the parent folders as namespaces:

add_filter('timber/loader/loader', function($loader) {
  $loader->addPath(Feature::getOption('flynt-components', 0) . '/Block', 'Block');
  $loader->addPath(Feature::getOption('flynt-components', 0) . '/List', 'List');
  // etc…
  return $loader;
});

To reference it like this in the twig templates:

{{ include '@Block/Button/index.twig' }}

Did you thought about this already? If so, why did you chose the current way? Before start working on a POC I thought asking for your thoughts first 🙏

Thanks!

domtra commented 5 years ago

Hi Fabian,

thanks for your question. The answer depends on what exactly it is you are trying to achieve. flynt-core does not make a lot of assumption about your file structure and can be modified any way you like. the flynt-starter-theme, however, has implemented our best practices. These include a flat file structure of components.

Our definition of a component is a broad one. We very rarely share markup or anything else between components. A component should be easily transferable to other projects, without having to think too much about dependencies.

The example that you give includes a twig template into another one. We hardly ever do this. When we do, we usually group the partial in another component. For example in Component/DocumentDefault/Partials/*.twig. Those we can include via the path itself, without the need for modification of the loader paths. The theme path should be already added to the loader paths in the flynt-starter-theme. One situation when we do something like this, is with form fields.

An alternative approach to just including twig partials, is to dynamically include a subcomponent into a specific component. For example, in ListPosts you could add the following filter in order to get some component composition.

add_filter('Flynt/dynamicSubcomponents?name=ListPosts', function ($areas, $data, $parentData) {
    $areas['teasers'] = array_map(function($post) {
        return [
            'name' => 'TeaserPost',
            'customData' => [
                'post' => $post,
            ],
        ];
    }, $data['posts']);
    return $areas;
}, 10, 3);

Then in the twig template of ListPosts you render this area like

{{ area('teasers') }}

This way, all the data preparations from the addComponentData filter will be executed and all javascript and css from the subcomponent TeaserPost will also be loaded. And this is usually what we want.

To answer your first question, however, it is possible to group components. The only thing that needs to be done to use a component, is to register its path. In Features/Components/functions.php we just register every subdirectory of the $componentPath. You could modify this behavior in a general way, or call Flynt\registerComponent for special cases, as well.

I hope this helps you with your structure / decision. Let us know, if you need any more assistance.