Metadata-Version: 2.5
Name: collective.blicca.footerblocks
Version: 1.0.0a2
Summary: Blicca rendering of editable footer blocks (collective.volto.footer) on stock Plone and plone.pageletlayout sites
Project-URL: Homepage, https://github.com/collective/collective.blicca.footerblocks
Project-URL: Documentation, https://github.com/collective/collective.blicca.footerblocks
Project-URL: Repository, https://github.com/collective/collective.blicca.footerblocks.git
Project-URL: Issues, https://github.com/collective/collective.blicca.footerblocks/issues
Author-email: Maik Derstappen <md@derico.de>
License: GPL-2.0-or-later
Keywords: CMS,Plone
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Plone
Classifier: Framework :: Plone :: 6.2
Classifier: Framework :: Plone :: Addon
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Requires-Dist: collective-volto-footer
Requires-Dist: plone-blicca-auroraeditor>=1.0.0a2
Requires-Dist: plone-rest
Requires-Dist: plone>=6.2
Provides-Extra: pageletlayout
Requires-Dist: plone-pageletlayout; extra == 'pageletlayout'
Provides-Extra: test
Requires-Dist: plone-app-multilingual; extra == 'test'
Requires-Dist: plone-app-testing; extra == 'test'
Requires-Dist: plone-pageletlayout; extra == 'test'
Requires-Dist: plone-testing; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Requires-Dist: pytest-plone>=0.5.0; extra == 'test'
Requires-Dist: requests; extra == 'test'
Description-Content-Type: text/markdown

# collective.blicca.footerblocks

An **editable site footer** for Plone 6 Blicca, built from Aurora blocks.

Editors compose the footer in the Aurora block editor, the same way they
compose a page: text, links, lists, and any installed Aurora block add-on.
The footer is stored once, usually on the site root, and rendered
server-side at the bottom of every page. A language folder or subsite can
carry its own footer, which then replaces the site-wide one below that
point.

The footer content is stored in the `footer` field that
[collective.volto.footer](https://github.com/collective/collective.volto.footer)
defines.
This package is the Blicca-Plone half: it renders that field through
[plone.blicca.auroraeditor](https://github.com/derico-de/plone.blicca.auroraeditor)
and mounts the Aurora editor on it.

## Features

- **Blocks in the footer.** Paragraphs, links, lists, and every Aurora block
  add-on installed on the site, for example an actions block for the site
  actions or a promo block for a closing call to action.
- **Inherited down the tree.** The footer of the nearest ancestor that has
  the editable-footer behavior is shown. Enable the behavior on a folder type
  to give a section its own footer.
- **One footer per language.** An opt-in profile makes every
  plone.app.multilingual language root folder a footer carrier, so `/de` and
  `/en` each edit and render their own.
- **Styled like page content.** The footer's blocks are wrapped in the same
  scope root as a page body, so the shared blocks stylesheet and every block
  add-on's stylesheet apply unchanged.
- **Invisible until authored.** A site without an authored footer renders no
  footer element at all. No empty band, no placeholder text.

## Requirements

- Plone 6.2 or later — stock Plone works out of the box, with Barceloneta
  or any Diazo theme
- `plone.blicca.auroraeditor` 1.0.0a2 or later
- `collective.volto.footer`, for the storage behavior
- `plone.rest`

All of these are declared as dependencies and pulled in on install.


## Installation

Add the package to your project's dependencies:

```toml
# pyproject.toml
dependencies = [
    "collective.blicca.footerblocks",
]
```

Then install **Collective Blicca Footerblocks** from Plone's Add-ons control
panel, or apply the `collective.blicca.footerblocks:default` GenericSetup
profile. Installing it:

- installs `collective.volto.footer` and `plone.blicca.auroraeditor` if
  they are not installed yet, which enables the editable-footer behavior on
  the Plone Site type;
- places the footer viewlet in Plone's footer, directly above the footer
  portlets (`plone.footer`), colophon and site actions; on a
  `plone.pageletlayout` site the same element is placed in the page layout,
  directly above the copyright, colophon and site-actions rows;
- makes every page load the blocks stylesheets, so footer blocks are styled
  on pages that are not block pages themselves.


## Editing the footer

1. Log in with a role that may edit the site root (or the folder that
   carries the footer).
2. Open any page in the Aurora editor and pick the **Footer** tab on top of
   the edit area. The tab is there before the first footer block is authored.
3. Compose the footer in the Aurora editor and save. You are taken back to
   the page, footer on display.

The footer surface starts directly with footer content: it does not show the
carrier site's or folder's document title, because that metadata is not part
of the published footer.

The **Footer** tab sends the page it sits on along, as the `origin` request
parameter (`<carrier>/@@edit-footer?origin=/Plone/de/page`). The footer
surface then shows that page's tab strip — **Blocks** and **Content** lead
back to the page, not to the carrier — and after save or cancel the author
lands on that page again, footer on display.

The editor can also be opened directly at `<carrier>/@@edit-footer`, where
the carrier is the site root or a folder with the editable-footer behavior.
Without an origin the strip offers the Footer tab alone: a site root or
folder has no blocks canvas of its own.

## Per-language footers

On a multilingual site the language root folders (`LRF`) are not footer
carriers out of the box: `collective.volto.footer` puts the editable-footer
behavior on the Plone Site type and nothing else. `/de` and `/en` therefore
have no `@@edit-footer`, and the **Footer** tab of a page below them opens
the site-wide footer instead.

Apply the `collective.blicca.footerblocks:multilingual` profile to change
that. It adds the behavior to the `LRF` type, and from then on every language
folder edits and renders a footer of its own. The existing language folders
become carriers immediately — a Dexterity object provides its behaviors'
marker interfaces the moment the type names them, so no content is migrated.
The profile requires plone.app.multilingual, and it is opt-in on purpose: a
multilingual site that wants one shared footer for all languages simply does
not apply it.

Extra profiles are not listed in the Add-ons control panel. Apply this one
from `portal_setup` → **Import**, choosing *Collective Blicca Footerblocks:
per-language footers* as the profile.

Applying the profile
also copies the inherited footer into every language that has none, in the
same transaction, and the published site is unchanged when it finishes. Each
language then owns its copy and is edited on its own; a site that would
rather start from empty language footers can clear them afterwards.

The same seeding is available on its own, and is idempotent:

```python
from collective.blicca.footerblocks.multilingual import seed_language_footers

seed_language_footers(portal)
```

To give a section its own footer, enable the
`collective.volto.footer.editable` behavior on that section's content type
in the Dexterity control panel, then edit the footer on that object. Pages
below it show that footer; pages elsewhere keep the site-wide one. An
ancestor that carries the behavior but has never had its footer authored
shows no footer, it does not fall back to the footer above it. This mirrors
how Volto's `@inherit` expander resolves the field.


## Rendered markup

```html
<div class="element-footerblocks">
  <div class="aurora-blocks-view">…rendered blocks…</div>
</div>
```

On stock Plone this sits inside `main_template`'s
`<footer id="portal-footer-wrapper">`, before the footer portlets, which is
why the element is a `<div>` and not a `<footer>` of its own (a nested
`<footer>` is invalid HTML). On a `plone.pageletlayout` site it is a layout
element between the page body and the copyright row.

A Diazo theme decides where that markup ends up. Barceloneta's `rules.xml`
moves every child of `#portal-footer-wrapper` that is not one of its own
`.row`s to the end of `<body>`, so on Barceloneta the footer blocks render
*below* the theme's copyright/colophon/site-actions footer, outside its
`<footer>`. A theme that wants the footer-blocks above its own footer copies
`.element-footerblocks` into place with a rule of its own.

The element is emitted only when the footer has blocks, and it is suppressed
on every Aurora edit surface — `@@edit-footer`, so the content being edited
is not repeated below the editor, and the page's `@@aurora-edit` canvas and
`@@edit-metadata` form, so the frame around the editor stays the same
whichever tab is showing. Visitors to a site without an authored footer get
no footer-blocks element at all.

`.aurora-blocks-view` is the public scope root of the shared blocks CSS and
of every block add-on's scoped stylesheet, so a theme styles footer blocks
exactly as it styles blocks in a page body. Theme the footer band itself
through `.element-footerblocks`.

## How it works

- **Storage.** The footer is the `footer` JSON field of the
  `collective.volto.footer.editable` behavior. It holds one Aurora container
  block whose tree carries the text and any block add-on's nodes.
- **Rendering.** `footer.footer_blocks_html()` walks up the acquisition
  chain from the current page to the nearest object with the behavior,
  reads its persisted footer value, and renders the blocks through the same
  pipeline that renders a page body. Only a persisted value counts; the
  behavior's schema default is ignored, which is what keeps an unauthored
  footer invisible. One viewlet renders it
  (`collective.blicca.footerblocks.footerblocks`, in Plone's `IPortalFooter`
  manager, before the footer portlets), on stock Plone and in
  plone.pageletlayout's slot layout, whose footer landmark renders the same
  manager.
- **Editing.** An ``IEditSurfaceTab`` subscriber resolves the nearest footer
  carrier and puts a **Footer** tab in the Aurora editor's tab strip when the
  current user may modify that carrier. The `@@edit-footer` page mounts the Aurora editor on its footer
  field, a `PATCH` to `@footerblocks` saves the container after running the
  block deserialization transformers, and a browser `GET` on `@footerblocks`
  redirects to the page the author came from (the `origin` parameter the tab
  sends along), or to the carrier, after save or cancel.
- **Stylesheets.** On stock Plone an `IHtmlHead` viewlet emits the blocks
  stylesheet links.

## Development

```shell
uv run pytest
```

The tests cover the pagelet, the editing surface (including an HTTP-level
test through an in-process ZServer), and the installed profile.

Every change to a GenericSetup profile XML file needs an upgrade step, even
in an alpha release. Scaffold it with `plonecli add upgrade_step`.

## License

GPL-2.0-or-later

## Author

Maik Derstappen, [derico](https://derico.de), <md@derico.de>
