{"id":13606054,"url":"https://github.com/wintercms/wn-blocks-plugin","last_synced_at":"2025-05-13T16:31:37.581Z","repository":{"id":81000570,"uuid":"603123328","full_name":"wintercms/wn-blocks-plugin","owner":"wintercms","description":"Block based content management plugin for Winter CMS.","archived":false,"fork":false,"pushed_at":"2025-04-24T15:41:53.000Z","size":171,"stargazers_count":22,"open_issues_count":5,"forks_count":5,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-06T23:31:12.622Z","etag":null,"topics":["blocks","hacktoberfest","laravel","wintercms"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wintercms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"wintercms","open_collective":"wintercms"}},"created_at":"2023-02-17T17:02:32.000Z","updated_at":"2025-04-24T17:53:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"8914da0c-431d-4716-8af1-c49a16d0c6e6","html_url":"https://github.com/wintercms/wn-blocks-plugin","commit_stats":{"total_commits":64,"total_committers":7,"mean_commits":9.142857142857142,"dds":0.53125,"last_synced_commit":"3946f8f80010831c65e0d3b3925d5530e56314bc"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wintercms%2Fwn-blocks-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wintercms%2Fwn-blocks-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wintercms%2Fwn-blocks-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wintercms%2Fwn-blocks-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wintercms","download_url":"https://codeload.github.com/wintercms/wn-blocks-plugin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253542651,"owners_count":21924852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blocks","hacktoberfest","laravel","wintercms"],"created_at":"2024-08-01T19:01:05.574Z","updated_at":"2025-05-13T16:31:37.522Z","avatar_url":"https://github.com/wintercms.png","language":"PHP","funding_links":["https://github.com/sponsors/wintercms","https://opencollective.com/wintercms"],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# Blocks Plugin\n\n![Blocks Plugin](https://github.com/wintercms/wn-blocks-plugin/blob/main/.github/banner.png?raw=true)\n\n[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/wintercms/wn-blocks-plugin/blob/main/LICENSE)\n\nProvides a \"block based\" content management experience in Winter CMS\n\n\u003e**NOTE:** This plugin is still in development and is likely to undergo changes. Do not use in production environments without using a version constraint in your composer.json file and carefully monitoring for breaking changes.\n\n## Installation\n\nThis plugin is available for installation via [Composer](http://getcomposer.org/).\n\n```bash\ncomposer require winter/wn-blocks-plugin\n```\n\nAfter installing the plugin you will need to run the migrations and (if you are using a [public folder](https://wintercms.com/docs/develop/docs/setup/configuration#using-a-public-folder)) [republish your public directory](https://wintercms.com/docs/develop/docs/console/setup-maintenance#mirror-public-files).\n\n```bash\nphp artisan migrate\n```\n\n\u003e**NOTE:** In order to have the `actions` support function correctly, you need to load `/plugins/winter/blocks/assets/dist/js/blocks.js` after the Snowboard framework has been loaded.\n\n## Core Concepts\n\n### Blocks\n\nThis plugin manages the concept of \"blocks\" in Winter CMS. Blocks are self contained pieces of structured content that can be managed and rendered in a variety of ways.\n\nBlocks can be provided by both plugins and themes and can be overridden by themes.\n\n### Actions\n\nThis plugin also introduces the concepts of \"actions\"; a way to define and execute client side actions that can be triggered by various events. Currently, actions are only defined in the `$/winter/blocks/meta/actions.yaml` file and must exist as a function on the `window.actions` object in the frontend keyed by the action's identifier that receives the `data` object as the first argument and (optionally) the `event` object that triggered the action as the second argument.\n\n\u003e**NOTE:** This is very much a WIP API and is subject to change. Feedback very much welcome here for ideas around how to register, manage, extend, and provide actions to the frontend.\n\n### Tags\n\nBlocks may have one or more tags, which is a way of defining and grouping blocks. For example, you may have a Gallery block which allows only \"image\" tagged blocks to be used, or a container block which allows all \"content\" tagged blocks but does not allow another \"container\" tagged block within.\n\nTags are defined in the blocks, and can be used to filter the available blocks in the Blocks form widget.\n\n\n## Registering Blocks\n\nThemes can have their blocks automatically registered by placing `.block` files in the `/blocks` folder and subfolders.\n\nPlugins can register blocks by providing a `registerBlocks()` method in their Plugin.php file. The method should return an array of block definitions in the following format:\n\n```php\npublic function registerBlocks(): array\n{\n    return [\n        'example' =\u003e '$/myauthor/myplugin/blocks/example.block',\n    ];\n}\n```\n\n\u003c!--\n    @TODO: For future implementation, consider performance hit of scanning directory\n\n    Plugins can also have their content blocks be automatically registered by placing `.block` files in the `/blocks` folder and subfolders of the plugin.\n--\u003e\n\n\n## Block Definition\n\nBlocks are defined as `.block` files that consist of 2 to 3 parts:\n\n- A YAML configuration section that defines the block's name, description, and other metadata as well as the block's properties and the form used to edit those properties.\n- A PHP code section that allows for basic code to be executed when the block is rendered, similar to a partial.\n- A Twig template section that defines the HTML markup template of the block.\n\nWhen there are two parts, they are the Settings (YAML) \u0026 Markup (Twig) sections.\n\nThe following property values (name, description, etc) can be defined in the Settings (YAML) section of the `.block` files:\n\n```yaml\nname: Example\ndescription: Example Block Description\nicon: icon-name\ntags: [] # Defines the tags that this block is associated with\npermissions: [] # List of permissions required to interact with the block\nfields: # The form fields used to populate the block's content\nconfig: # The block configuration options\n```\n\nBlocks can use components in them, although they may face lifecycle limitations with complex AJAX handlers similar to component support in partials.\n\n### Fields and Configuration\n\nBlocks may define both `fields` as well as a `config` property in the Settings. Both of these parameters accept a [form schema](https://wintercms.com/docs/backend/forms#form-fields), but serve different purposes. In general, `fields` should contain the fields that actually fill in the content of the block, whereas the `config` should contain the fields that define the appearance or structure of the block itself. Fields are displayed within the block in the `blocks` form widget and configuration is displayed in an Inspector which can be shown by clicking on the \"cogwheel\" icon of a block in the `blocks` form widget.\n\nFor example, let's say you have a **Title** block which can display a heading tag in your content. You may optionally want to align it to left, center or right, and define which heading tag to use. The best practice would be to have a `content` field in the `fields` definition, because it's the actual content being displayed. The `alignment` and `tag` would become part of the `config` configuration.\n\n**Example:**\n\n```\nname: Title\ndescription: Adds a title\nicon: icon-heading\ntags: [\"content\"]\nfields:\n    content:\n        label: false\n        span: full\n        type: text\nconfig:\n    size:\n        label: Size\n        span: auto\n        type: dropdown\n        default: h2\n        options:\n            h1: H1\n            h2: H2\n            h3: H3\n            h4: H4\n            h5: H5\n    alignment_x:\n        label: Alignment\n        span: auto\n        type: dropdown\n        default: center\n        options:\n            left: Left\n            center: Centre\n            right: Right\n==\n{% if config.alignment_x == 'left' %}\n    {% set alignment = 'text-left' %}\n{% elseif config.alignment_x == 'center' or not config.alignment_x %}\n    {% set alignment = 'text-center' %}\n{% elseif config.alignment_x == 'right' %}\n    {% set alignment = 'text-right' %}\n{% endif %}\n\n\u003c{{ config.size }} class=\"{{ alignment }}\"\u003e\n    {{ content }}\n\u003c/{{ config.size }}\u003e\n```\n\n## Using the `blocks` FormWidget\n\nIn order to provide an interface for managing block-based content, this plugin provides the `blocks` FormWidget. This widget can be used in the backend as a form field to manage blocks.\n\nThe `blocks` FormWidget supports the following additional properties:\n\n- `allow`: An array of block types that are allowed to be added to the widget. If specified, only those block types listed will be available to add to the current instance of the field. You can define either a straight array of individual blocks to allow, or define an object with `tags` and/or `blocks` to allow whole tags or individual blocks.\n- `ignore`: A list of block types that are not allowed to be added to the widget. If not specified, all block types will be available to add to the current instance of the field. You can define either a straight array of individual blocks to ignore, or define an object with `tags` and/or `blocks` to ignore whole tags or individual blocks.\n- `tags`: A list of block tags that are allowed to be added to the widget. If specified, only block types that have at least one of the listed tags will be available to add to the current instance of the field.\n\nThose properties allow you to limit the block types that can be added to a specific instance of the widget, which can be very helpful when building \"container\" type blocks that need to avoid including themselves or only support a specific set of blocks as \"children\".\n\n### Examples\n\nThe `button_group` block type only allows a `button` block to be added to it:\n\n```yaml\nbuttons:\n    label: Buttons\n    span: full\n    type: blocks\n    allow:\n        - button\n```\n\nThe `container` block type allows any block called `title`, or has a tag of `content`, to be added to it:\n\n```yaml\ncontainer:\n    label: Container\n    span: full\n    type: blocks\n    allow:\n        blocks:\n            - title\n        tags:\n            - content\n```\n\nThe `columns_two` block type allows every block except for itself to be added to it:\n\n```yaml\nleft:\n    label: Left Column\n    span: left\n    type: blocks\n    ignore:\n        - columns_two\nright:\n    label: Right Column\n    span: right\n    type: blocks\n    ignore:\n        - columns_two\n```\n\n### Integration with the Winter.Pages plugin:\n\nInclude the following line in your layout file to include the blocks FormWidget on a Winter.Pages page:\n\n```twig\n{variable type=\"blocks\" name=\"blocks\" tags=\"pages\" tab=\"winter.pages::lang.editor.content\"}{/variable}\n```\n\n\n## Rendering Blocks\n\n### Using Twig\n\nTwig functions are provided by this plugin for rendering blocks.\nYou can then use the following Twig snippet to render the blocks data in your layout:\n\n```twig\n{{ renderBlocks(blocks) }}\n```\n\nYou can use it anywhere an expression is accepted:\n\n```twig\n{{ ('\u003cp\u003eSome text\u003c/p\u003e' ~ renderBlocks(blocks) ~ '\u003cp\u003eSome more text\u003cp/\u003e') | raw }}\n\n{% set myContent = renderBlocks(blocks) %}\n```\n\nIf you need to render a single block, you can use the `renderBlock` function:\n\n```twig\n{{ renderBlock({\n    '_group':'title',\n    'content':'Lorem ipsum dolor sit amet.',\n    'alignment_x':'left',\n    'size':'h1',\n}) }}\n\n{{ renderBlock('title', {\n    'content':'Lorem ipsum dolor sit amet.',\n    'alignment_x':'left',\n    'size':'h1',\n}) }}\n```\n\n### Using a partial\n\nIf you need to customize the rendering of blocks according to their group, you can use a special `blocks.htm` partial in your theme:\n\n```twig\n{% for blockIndex, block in blocks %}\n    {# Adding blocks to the following array allows them to implement their own containers #}\n    {% if block._group in [\"hero\", \"section\"] %}\n        {{ renderBlock(block) }}\n    {% else %}\n        \u003csection class=\"flex flex-wrap items-center mx-auto max-w-screen-xl\"\u003e\n            \u003cdiv class=\"w-full p-4\"\u003e\n                {{ renderBlock(block) }}\n            \u003c/div\u003e\n        \u003c/section\u003e\n    {% endif %}\n{% endfor %}\n```\n\nYou can then use the following Twig snippet to render the block data in your layout:\n\n```twig\n{% partial 'blocks' blocks=blocks %}\n```\n\n### Using PHP\n\n```php\nuse Winter\\Blocks\\Classes\\Block;\n\n// Render a single block from stored data\nBlock::render($model-\u003eblocks[0]);\n\n// Render an array of blocks from stored data\nBlock::renderAll($model-\u003eblocks);\n\n// Render a single block manually\nBlock::render('title', [\n    'content' =\u003e 'Lorem ipsum dolor sit amet.',\n    'alignment_x' =\u003e 'left',\n    'size' =\u003e 'h1',\n]);\n\n// Render a single block manually using only array data\nBlock::render([\n    '_group' =\u003e 'title',\n    'content' =\u003e 'Lorem ipsum dolor sit amet.',\n    'alignment_x' =\u003e 'left',\n    'size' =\u003e 'h1',\n]);\n```\n\n\n## Integrating with TailwindCSS / CSS Purging\n\nIf your theme uses CSS class purging (i.e. Tailwind), it can be useful to add the following paths to your build configuration to include the styles for any blocks defined by the theme or plugins.\n\n```js\n// tailwind.config.js\nmodule.exports = {\n    content: [\n        // Winter.Pages static page content\n        './content/**/*.htm',\n        './layouts/**/*.htm',\n        './pages/**/*.htm',\n        './partials/**/*.htm',\n        './blocks/**/*.block',\n\n        // Blocks provided by plugins\n        '../../plugins/*/*/blocks/*.block',\n    ],\n};\n```\n\n\n## Feedback\n\n\u003e The Winter.Blocks is perfect for my block-based themes. I've been looking for something like this for a long time\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwintercms%2Fwn-blocks-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwintercms%2Fwn-blocks-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwintercms%2Fwn-blocks-plugin/lists"}