.. include:: /Includes.rst.txt .. _usage: ===== Usage ===== Look shows the frontend markup of a content element in the page module, inside an isolated frame. The view helper :html:`` builds that frame around whatever markup it is given. Where the markup comes from depends on how the site renders its content elements, and there are two ways: .. _usage-two-ways: Two ways to a preview ===================== **Content Blocks with Fluid Components**, the preferred way The backend preview of a Content Block renders the same Fluid component as the frontend template, inside the page module request. One component is the single source of truth for the website and the page module, no TypoScript is involved, and the preview costs one component rendering. Take this way wherever Content Blocks and components are in use. See :ref:`usage-content-blocks`. **Classic content types and plugins through TypoScript** Content types rendered the classic way (:typoscript:`tt_content` as :typoscript:`CASE` object, :typoscript:`FLUIDTEMPLATE`, data processors) and plugins (Extbase, :typoscript:`USER` objects) register a preview template per type. There, :html:`` hands the record to Look, which renders it with the frontend TypoScript of its page in a request of its own. This is the way for themes and site packages that are not built on Content Blocks, for example the TYPO3 v14 default theme Camino or fluid_styled_content, and for anything that runs PHP of its own during rendering. See :ref:`usage-fluid-templates`. Why the second way does not render in the page module ----------------------------------------------------- A Fluid component is a template. Frontend TypoScript is code: data processors query the database, :typoscript:`USER` objects run arbitrary PHP, Extbase plugins bootstrap a whole MVC stack that expects a frontend. Running that in the page module request would mean running it inside an authenticated backend request, and the frontend has habits that do not belong there: * Plugins send headers with PHP's :php:`header()` (redirects, cookies, cache control) and would send them for the page module's response. * Extbase clears frontend caches on errors and keeps its own configuration manager, which would take the backend request for a frontend one from then on. * TypoScript rendering leaves state behind: :php:`$GLOBALS['TSFE']` in TYPO3 13, the page renderer's language, context aspects. * An exception, a fatal error or a slow query in one element would break or stall the whole page module, not one preview. Rendering in a separate request keeps all of that in that request. The page module only emits a description of what to render, the frame fetches the result with a short-lived token, and a failing element shows an error inside its frame while the rest of the page module works. The trade-off is one additional request per visible element, loaded lazily. See :ref:`security-preview-request` for how the request is protected. Both ways can be combined in one installation: Content Blocks bring their own preview template, classic types and plugins get theirs via TSconfig. .. contents:: :local: :depth: 1 .. _usage-content-blocks: Previews for Content Blocks with Fluid Components ================================================= `Content Blocks `__ render the file :file:`templates/backend-preview.html` of a content block in the page module. With `Fluid Components `__ the frontend template of the block is a single component call, and the backend preview makes the same call inside the Look frame. The component collection of the site package -------------------------------------------- A component collection makes the components of a directory available under a Fluid namespace: .. code-block:: php :caption: EXT:my_site/Classes/Components/ComponentCollection.php setTemplateRootPaths([ 'EXT:my_site/Resources/Private/Components/', ]); return $templatePaths; } } The component ------------- The component receives the record and renders the element. It is the only place where the markup of the element lives: .. code-block:: html :caption: EXT:my_site/Resources/Private/Components/Element/Textmedia/Textmedia.html

{record.header}

{record.bodytext}
The frontend template of the block ---------------------------------- The frontend template calls the component with the record Content Blocks provides as :html:`{data}`: .. code-block:: html :caption: EXT:my_site/ContentBlocks/ContentElements/textmedia/templates/frontend.html The backend preview of the block -------------------------------- The backend preview calls the same component, wrapped in the Look frame with the assets of the frontend build: .. code-block:: html :caption: EXT:my_site/ContentBlocks/ContentElements/textmedia/templates/backend-preview.html
Three things are worth noting: * :html:`` with a :html:`Content` section is the layout Content Blocks provides for backend previews. Without it, Content Blocks renders the template three times (header, content, footer) and the preview appears three times. * The markup inside the view helper is whatever your frontend produces. Here it is the component; it could also be a partial or plain HTML for blocks without components. Wrapping the element in the same container markup as the frontend page (:html:`
`) makes sure the grid and spacing rules of your CSS apply. * :html:`css` and :html:`js` take the assets of your frontend build. They are loaded inside the preview frame only, never in the backend itself. .. figure:: /Images/PreviewSection.png :alt: A content element with a coloured section background rendered in the page module :class: with-shadow Section backgrounds, decorative borders and buttons come from the site's own stylesheet. Why this way is preferred ------------------------- * The component is rendered directly. No TypoScript is calculated, no content object is resolved, the preview is as cheap as the frontend rendering of the element. * Frontend and preview cannot drift apart: a change to the component changes both. * Content Blocks hands the preview the same :php:`Record` object as the frontend, including resolved relations such as images. Hidden relations are shown in the backend by default. If the frontend hides unpublished images or child records, see :ref:`usage-tips` for how to make the preview do the same. .. _usage-fluid-templates: Previews for classic content types through TypoScript ===================================================== Content types without Content Blocks are rendered by the :typoscript:`tt_content` content object of the site's TypoScript: a :typoscript:`CASE` that picks a :typoscript:`FLUIDTEMPLATE` per type, with template paths and data processors such as :typoscript:`record-transformation`. For the page module, such types register a preview template with page TSconfig. Look renders the record inside that template with the same TypoScript the frontend uses. Register one template for all types ----------------------------------- Because the rendering comes from TypoScript, a single preview template serves every content type. Point each type to the same file: .. code-block:: typoscript :caption: EXT:my_site/Configuration/page.tsconfig mod.web_layout.tt_content.preview { text = EXT:my_site/Resources/Private/Templates/Preview/Content.html textmedia = EXT:my_site/Resources/Private/Templates/Preview/Content.html textpic = EXT:my_site/Resources/Private/Templates/Preview/Content.html bullets = EXT:my_site/Resources/Private/Templates/Preview/Content.html table = EXT:my_site/Resources/Private/Templates/Preview/Content.html my_teaser = EXT:my_site/Resources/Private/Templates/Preview/Content.html } In a site set, put the lines into the :file:`page.tsconfig` of the set. When the set depends on the theme's set, its TSconfig is loaded after the theme's and replaces the theme's own preview registrations. The preview template -------------------- The page module hands the template the record as :html:`{record}`, a :php:`Record` object of the Record API (TYPO3 13.4 and later). The template passes it to the view helper as :html:`record` and has no children: .. code-block:: html :caption: EXT:my_site/Resources/Private/Templates/Preview/Content.html What happens when the preview renders: #. In the page module, the view helper emits the frame without content, only with a signed description of what to render: the record, its workspace and language, the content object and the frame options. No PHP of the site runs in the page module request. #. When the frame comes into view, Look's script in the page module exchanges the description for a token at an authenticated backend route. The token is valid for a few seconds and becomes the frame's :html:`src`. #. The preview request, a public backend route that accepts only such a token, calculates the frontend TypoScript of the record's page (rootline, :sql:`sys_template` rows and the sets of the site, the same way Extbase does it for backend modules) and renders the :typoscript:`tt_content` content object for the record with the core's :php:`ContentObjectRenderer`. Templates, partials, layouts and data processors are those of the site's TypoScript. A site package that overrides template paths or adds content types needs no second configuration for the previews. Because the element is rendered in its own request, whatever the site's templates, data processors or plugins do stays there: an exception, a slow data processor or a plugin that sends headers affects one frame, never the page module. See :ref:`security-preview-request` for the details of the token and the request. While rendering, hidden relations such as unpublished images stay hidden as on the website, and image processing runs immediately instead of being deferred as in other backend requests. The preview request has no backend user; workspace and language come from the token. Example: a theme's colour scheme -------------------------------- Themes often expect a class on the body, for example a colour scheme chosen in the site settings. :html:`` reads a setting of the site the record's page belongs to. The TYPO3 v14 default theme Camino stores its scheme in :yaml:`camino.colorScheme`: .. code-block:: html :caption: EXT:my_site/Resources/Private/Templates/Preview/Content.html Switching the scheme in the site settings switches the previews, because the frame carries the same body class as the website. Rendering through another content object ---------------------------------------- By default the record is rendered through :typoscript:`tt_content`. The argument :html:`typoscriptObjectPath` selects another content object, for example :typoscript:`lib.contentElement` to skip the :typoscript:`CASE` and render the element's FLUIDTEMPLATE directly: .. code-block:: html .. note:: The core view helper :html:`f:cObject` also renders content objects in the backend, but it does not put the calculated TypoScript on the request. TypoScript references such as :typoscript:`tt_content.default =< lib.contentElement` are then not resolved and the preview stays empty without an error. Use the :html:`record` argument instead. Rendering the element yourself ------------------------------ A preview template can also render the frontend markup directly, for example with a partial of the site package. Templates written for the frontend's :typoscript:`record-transformation` data processor work unchanged, because they receive the same :php:`Record` object: .. code-block:: html :caption: EXT:my_site/Resources/Private/Templates/Preview/Textmedia.html Note that the page module gives preview templates no layout or partial root paths of their own; :html:`f:render partial` needs an absolute :html:`EXT:` path. This renders in the page module request, like a Content Blocks preview; hidden relations and deferred image processing are then your concern, see :ref:`usage-tips`. See the `TSconfig reference `__ for the details of :typoscript:`mod.web_layout.tt_content.preview`. .. _usage-choosing: Choosing between the two ways ============================= .. list-table:: :header-rows: 1 :widths: 30 35 35 * - - Content Blocks with components - Classic types through TypoScript * - Source of the markup - The component, called directly - The site's TypoScript, rendered by the ContentObjectRenderer * - Where the site's PHP runs - In the page module request - In a separate preview request * - Preview registration - :file:`backend-preview.html` of the block - :typoscript:`mod.web_layout.tt_content.preview` per type * - Record in the template - :html:`{data}` - :html:`{record}` * - Cost per preview - One component rendering in the page module - One additional request per visible element (token exchange plus rendering), loaded lazily * - Fits - Sites built on Content Blocks and Fluid Components - Themes and site packages with classic rendering: Camino, fluid_styled_content, own CTypes Where both are possible, take the component. Where the rendering lives in TypoScript, take the :html:`record` argument. .. _usage-viewhelper: The view helpers ================ look:backend.contentPreview --------------------------- .. code-block:: html .. confval-menu:: :name: viewhelper-arguments :display: table :type: :default: .. confval:: record :name: viewhelper-record :type: :php:`TYPO3\CMS\Core\Domain\RecordInterface` :default: (none) Render this record with the frontend TypoScript of its page in a separate request instead of the children. Usually the :html:`{record}` variable of a preview template registered via :typoscript:`mod.web_layout.tt_content.preview`. The view helper must have no children then. .. confval:: typoscriptObjectPath :name: viewhelper-typoscriptobjectpath :type: string :default: :code:`tt_content` With :html:`record`: dotted path of the content object in the page's frontend TypoScript that renders the record. .. confval:: scale :name: viewhelper-scale :type: float :default: extension configuration :confval:`contentPreview.scale ` (0.5) Factor the frontend is scaled down with inside the preview. :code:`0.5` shows the site at half size, :code:`1` at its natural size. The frame is always as wide as the page module column; the scale decides how much of the frontend width fits into it. .. confval:: height :name: viewhelper-height :type: integer :default: extension configuration :confval:`contentPreview.height ` (0) Maximum height of the preview in pixels. Elements that are taller are cut off and fade out at the bottom, so editors see that there is more. :code:`0` means no limit: the frame grows with its content. .. figure:: /Images/PreviewHeightLimit.png :alt: A preview cut off at a fixed height with a fade-out at the bottom :class: with-shadow A preview with :html:`height="250"`. The fade-out marks that the element continues below. .. confval:: bodyClass :name: viewhelper-bodyclass :type: string :default: (empty) Class attribute of the :html:`` inside the preview frame. Use it when your stylesheet expects a class on the body, for example a theme or a scope class. .. confval:: css :name: viewhelper-css :type: array :default: [] Stylesheets to load inside the frame, as :code:`EXT:` paths or public URLs. Usually the CSS bundle of your frontend build. Look's own small stylesheet (scaling, fade-out) is always loaded first. .. confval:: js :name: viewhelper-js :type: array :default: [] JavaScript modules to load inside the frame, as :code:`EXT:` paths or public URLs. They are loaded as :html:`