All docs pages: Sites

Sites

Drupal

In short

Wanigan shows your local Drupal site, names every part of each page, and saves your changes through Drupal’s own APIs, as you, with a revision where Drupal keeps one. This page lists everything it covers on Drupal, what each save goes through, and what it refuses and why.

On this page

What it covers

A Drupal page is built from many pieces: templates, fields of a piece of content, blocks placed in regions, views, menus, Layout Builder sections, components. To change one word you first have to find which of them holds it, and then the right form to change it in. Wanigan finds that for you and saves through Drupal itself.

Without the helperWith the helper
Finding the siteFrom .ddev, .lando.yml or a dev script in the projectThe same
Naming the partsTemplates and components, from Twig debug’s own comments while Twig debug is onEvery template, component, piece of content, field, block, view and menu, read through core’s own render
Why a part looks as it doesIts template file, and whose code that isIts suggestions, preprocess steps and hooks, timed, its variables (secrets hidden), cache metadata and queries
Saving changesNoWords through Make it real; any part through Drupal’s own form for it
Moves and Take outNoWhere Drupal itself keeps an order, each with Undo
Component libraryNoSingle-directory components and the block library’s blocks, pictured
Go to, and content changesPages the view has seen; reloads when files changeEvery admin page, content, term, user and media item; reloads when content changes too

The helper names no module. Anything built on Drupal core’s render pipeline, theme system, entities, fields, forms and configuration shows up through it, and a few modules that keep words where core’s saves cannot reach get an adapter.

Try it on Northstar

Northstar, the Drupal demo, is a made-up outdoor-goods shop on Drupal core. These three steps show the helper, a save and a refusal. The full how-to is in the site helper and Make real.

  1. Install the helper

    Open a product, such as the Lakeside Enamel Mug. Under Layers, choose Set up the Drupal helper…, read what it writes and runs, and press Install the helper. It runs four ddev commands, which can take a minute, then reloads the page with every part named.

    Northstar’s Lakeside Enamel Mug page just after the Drupal helper is installed: the Layers tree naming the product, its fields and the components that render them. Current beta · demo
    The left panel’s tree of page parts, now naming the product by its type and title, its fields by their labels, and the theme’s components nested inside them, beside the product page.
  2. Retype the title and make it real

    Select the product’s title (P), press E, type new words and press Enter. Open Edits (On a Mac, ⇧E; on Windows and Linux, Shift+E) and choose Make it real. The words are saved to the title of that product, in that language, as a new revision by you, and the edit becomes In the site, not verified until you run Verify.

    Edits after Make it real on the Lakeside Enamel Mug’s retyped title: the message “Saved … in the site, as revision …”, the edit In the site, not verified, and Verify. Current beta · demo
    The Edits panel lists the title edit with its old and new words. Its state now reads In the site, not verified, a Verify button sits under it, and a message at the bottom of the window says it was saved as a numbered revision.
  3. Try a page with a draft waiting

    The Ember Camp Mug has a newer draft waiting over the version visitors see. Retype its title the same way and choose Make it real: nothing is saved, and the edit says “This content has a newer draft than the version the page shows, and Wanigan does not save into a draft yet”, with Tell an agent… under it. Saving would leave the draft behind, so change it in Drupal’s form, which edits the draft.

    Edits on the Ember Camp Mug page: the title edit still a draft, the answer saying the product has a newer draft and Wanigan does not save into a draft yet, and Tell an agent… under it. Picture to come

    Picture: to come

    A screenshot of the real app, with the demo’s data, of what the title above says.

Finding the site

Wanigan reads the project’s own files and offers the address they name: a ddev project from .ddev/config.yaml, a Lando site from .lando.yml, or a dev script from package.json. It starts nothing to find them. Details are in Turning it on.

  • For a ddev site, Wanigan asks ddev whether the site is running, and Start it runs ddev start on your click. A Lando site or a dev script that does not answer is named, with how it is started; Wanigan does not start those.
  • The helper installs with ddev only. In a project with no .ddev folder Wanigan does not install it yet; the page is still shown, and Twig debug still names its templates.

Without the helper: Twig debug

Twig is the language Drupal’s templates are written in. When Twig debug is on, Drupal writes a comment around every template’s output saying which file printed it and which other file names it could have used. Switch it on in Configuration › Development › Development settings.

From those comments alone, Layers names each template and single-directory component, nested as the page nests them, and says whose code each file is from where it sits: core, contributed, or yours. A single-directory component is one whose template, styles and .component.yml (its props and slots) live in one folder.

With Twig debug off and no helper, Layers says “Nothing on this page says what made it”. You can still select a part and point an agent at it.

The helper module

The Drupal helper is a development-only module, wanigan_live, that Wanigan writes into the site’s modules/custom folder on your click and installs with ddev drush. A module is a package of code that adds to Drupal; this one adds nothing a visitor can see.

  • It switches on Twig development mode (debug on, Twig and render caching off) and keeps the settings it found in Drupal’s state, so removing the helper puts them back. Pages are slower meanwhile, as they are when you switch it on yourself.
  • It acts only for requests that carry the token Wanigan keeps in Drupal’s state, which only the live view sends. Every other request gets exactly what core makes, so the site looks the same in any other browser.
  • Its folder is listed in the repository’s .git/info/exclude, so git never sees it and it cannot be committed.
  • It carries a version (4 in this build). When the one in the site is older than your Wanigan’s, Wanigan says so and offers Update the helper…, which rewrites only its own folder.

What it adds, in the words of its install dialog:

  • What made every part of the page, read through Drupal core: its template and the suggestions it could have used, the preprocess and alter hooks that shaped it (each with its time and what it changed), its variables, cache tags and queries.
  • Edits any field where it shows, in Drupal’s own form for that one field, saved as a new revision by the user you are logged in as in the live view.
  • Moves blocks between regions, menu links, a field’s items and a display’s fields by dragging, through core, each with Undo, and says first when a move changes configuration every page shares.
  • Copies a template into your theme to override it, only when you ask.
  • Go to: admin pages and their tabs, content, terms, users and media.
  • One piece shown alone: a piece of content, a component with its examples, a block, or sample content where there is none yet.
  • Reloads the view when content changes in Drupal (an agent running drush, an editor saving), not only when files change.

How to install, update and remove it, and what happens when another Wanigan set it up, is in Turning it on.

Naming parts

With the helper, each part is named the way the site names it: a piece of content as “Product: Lakeside Enamel Mug”, a field by its label, a block, a region, a view or a menu by its name, a component by its .component.yml name. A template nothing else names keeps its file name. See the Inspector for how Layers shows them.

Each part also says what the site stores it as, so an edit finds it again after a reload or a reorder: an entity (Drupal’s word for a stored thing, such as a piece of content, a term or a user), a field and its item (a reference by what it points to, so a reorder does not lose it), a component inside a part, a block placement, a menu or menu link, a view, and a Layout Builder component by its id on the content it is shown for. A paragraph is named as itself, with the revision the page showed.

On Northstar, 318 of 394 parts were named this way, and a moved menu link kept its name as it moved.

What Make real saves

Make it real saves the words you typed on the page into the one thing that holds exactly those words. On Drupal that is one of these, chosen from what the helper says made the part:

Drupal: where words go
Words in…Saved throughChecks and revisions
A plain text field (string, string_long)The Entity API: the translation the page showed, and the one item of the field holding the old wordsA new revision by you; validated as Drupal’s own form for that field would, with the workflow; refused over a newer draft
Formatted text (text, text_long, text_with_summary)One run of words spliced into the stored text, its markup kept byte for byteSaved only when the field’s own text format shows nothing else changed
A field’s labelThe field’s own configuration saveRequired, at most 255 characters
A block’s titleThe block placement’s configurationRequired; your user needs the permission its form needs
The site’s name and slogan, where core’s branding block shows themThe site’s configurationName required; slogan at most 255 characters
A view’s header, footer or empty textThe view display that owns it, one run of words at a time, so its markup never enters the valueRefused while Views UI holds the view locked
A content menu link’s textIts title field, through the field saveThe same checks as a field
A Layout Builder inline blockIts layout, as Layout Builder’s own block form saves itA page’s own layout as a new revision; a default layout says how far it reaches first
A paragraph (the Paragraphs module)The page that holds it, as a new revision, through the Paragraphs adapterThe page’s workflow, log and checks
A form’s words (the Webform module)Webform’s own API, through the Webform adapterIn the form’s language or its translation; shared words say how many forms first
Any other field of the content the page showedThe stored-words search, through the Entity APIFound exactly once, as words; a new revision

Configuration

A field’s label, a block’s title, the site’s name and slogan, a view’s words and a webform are configuration: Drupal’s settings, kept in the database and usually exported to files in the code. The next configuration import puts back what is exported, so every such save says so. Export the configuration to keep the change.

Words the page shows in another language are saved to that language’s configuration translation, which needs the “translate configuration” permission. Words with no translation are never saved to another language.

A new address

Every save answers with the content’s address before and after. When a new title gives the page a new address, as it does on a site where the Pathauto module makes addresses from titles, the view goes to the new address instead of reloading the old one.

Words shown beyond this page

A Layout Builder default layout, which every page of a kind without its own layout shows, a Paragraphs Library item and a webform’s shared words say how far they reach before anything is saved. Make it real again to save them. More in Make real.

Edits through Drupal’s own forms

For a change that is more than words, choose Edit ▾ on a part. Under In the site · saved by Drupal as you, each way to change it opens beside the part: Drupal’s own form, saying “Drupal’s own form, saved by Drupal as you, as a new revision.” where the content keeps revisions, or for a single value, such as a block’s title, a short form Wanigan draws that Drupal checks when you save. Saving reloads the page.

A part that is…Opens
A field of a piece of contentThe content’s own form, narrowed to that one field and its widget. The whole content is validated as core does; it saves a new revision, and edits the newest version, so a draft is never written over.
A block placementThe block’s own form
Another configuration item, such as a view or a menuIts own edit page
A menu linkA content menu link’s form; any other link where its module defines it
Something Layout Builder lays outLayout Builder’s own page for that content
A template from core or a contributed moduleCreate override…: the template copied into your theme, on your word only. Refused when a file of that name is already in the theme, when the active theme is core’s or contributed, or without “administer themes”.
A componentIts props, with where they are written: the field that stores them, or the Twig code to override. Never saved from here.

Where a part cannot be changed here, the menu says why: your user may not, the field is computed or read only, no widget edits its type, or the content belongs to other content or is shown as one pinned revision of it.

Before you save, the sheet says whose code also runs on that save: the modules that implement the entity’s save hooks, or listen to a configuration save. Drupal core has no AI API, so Wanigan cannot list a Drupal site’s AI, and says so in the Inspector’s AI on this site.

Moves, inserts and Take out

Drag a part by its handle, or press M on a chosen part, to move it where Drupal itself keeps an order. Each move first checks the order is still what the page showed, and answers with the order as it is now when it is not.

What movesWhat the move saves
A field’s itemsThe field’s values in the new order, as a new revision. Refused when the page shows a different number of items than the field holds.
A theme region’s blocksEach block placement’s region and weight. A block can move into an empty region.
A menu levelEach link’s weight and parent, as the menu’s own form saves them. Links move between levels of one menu.
The fields of a displayThe display’s weights. Refused when Layout Builder arranges the display, or its template prints the fields one by one.
Layout Builder regionsThe layout, as Layout Builder’s own move saves it. Refused while Layout Builder holds unsaved changes.

Inserts add a block from the block library to a region, placed as the block form places one, or a new item to a field whose type can make a sample value. A new reference is never inserted, since it would create content of another kind, and a component is never inserted: core has no place that stores one.

Take out (On a Mac, ⇧X; on Windows and Linux, Shift+X) takes only the placement or reference away, never what it showed:

  • A block placement is switched off, not deleted, and stays in Block layout with its settings.
  • A menu link is switched off in the menu, not deleted.
  • A field item’s reference goes, and the content, media or file it pointed to stays. A Layout Builder component goes from the layout, and what it showed stays.
  • Refused where core would delete what the part showed: an inline block in a layout without revisions, or a file, image or other owned reference on content that keeps no revisions. A link with links under it is refused too.
  • Anything shared says where it shows and asks first. Taking something out of configuration says to export the configuration to keep it in code.

Undo puts a move or a removal back for ten minutes, and only while nothing else has changed what it touched.

The component library

The library (On a Mac, ⇧B; on Windows and Linux, Shift+B) lists what the site can place, as Drupal core lists it: its single-directory components and the blocks its block library offers. Each is pictured alone in the site’s own theme at a phone’s and a desktop’s width, with its props, slots and files.

  • Where it is used across the site: its placements in every theme, Layout Builder default and per-page layouts, and for a component the templates that include it, found by Drupal’s own Twig parser. It says what no search of stored data can see.
  • A component cannot be placed on a page by itself through core: Drupal keeps no such thing outside a template or a field, and the library says so. Blocks can be placed from it.
  • Seen in the real app on Northstar: 73 entries, pictured at exact sizes.

How the library looks and works is in Components.

Canvas

Canvas is a contributed page builder for Drupal that keeps a page’s design in its own component tree. In this build, Canvas pieces by their own ids are on the list of what is not built yet.

The stored-words search leaves a Canvas component tree’s inputs out, so it never writes into one. Words a Canvas page keeps there are not saved from here: change them in Canvas, or tell an agent from Edits.

What is refused, and why

Every refusal says why, and which kind of why. Drupal keeps no such thing means core stores those words nowhere it can write, so they are code: an agent or you change the code. Wanigan does not do it yet means core could save it and Wanigan does not, from here; change it in Drupal’s own form meanwhile.

Drupal keeps no such thing
Words in…What to do
Words typed into a Twig templateAn agent changes the template from a brief, in a copy in your theme when the template is not yours
A menu link a module writes in its links.menu.yml fileChange it where it is defined
The label of a base field (one a kind of content defines in code, such as a title)Change the code
A component’s props written in TwigCopy that template into your theme and change it there
Words a Webform token or computed element makesChange what makes them
Wanigan does not do it yet
Words in…What to do
Words a template prints through t() (an interface translation: Drupal’s translations of the words code prints)Change them under Interface translation, or in the template. A change there reaches every page that prints the same words.
An image’s caption, words across formatting, or words a media item embedded in the text showsDrupal’s form, or the media item
Content with a newer draft, or a page that shows a draftDrupal’s form, which edits the draft
A language the content has no translation in yetTranslate it in Drupal first
A field of a type Wanigan’s word saves do not modelThe stored-words search tries it first; otherwise Drupal’s form
Words a formatter Wanigan does not know shows, or a trimmed summaryDrupal’s form, or where the whole text shows
A paragraph inside a Layout Builder inline blockLayout Builder
A webform’s shared options in a translation, or a wizard page’s own button labelWebform’s form

Other refusals are about now: the content changed since the page loaded, several things hold the same words (each named), your user may not change it, or Drupal refused, in its own words. Reload and try again. More in Make real.

In depth

How the trace hooks core

The trace runs only for a main page request carrying the token. For that request, five of core’s own services run as subclasses of their core classes; each is swapped in only when the running core’s class has exactly the methods and signatures it was written against. For every other request each method calls core’s and returns its answer untouched, so the page is byte for byte what core makes.

WhatWhere in core it is read
Every template’s output becomes a partWhere a template’s final variables, file and output meet: the Twig engine (11.3 and later) or the theme manager (before). Each part is wrapped in wl:part comments outside core’s own debug comments.
What shaped a templateEach preprocess step, run exactly as core runs it, timed, with the variables it changed
SuggestionsThe file names core offered, most specific first, which exist in the theme, and which was chosen
HooksEvery module’s and theme’s implementation, timed, in core’s own order
Cache and costEach element’s cache metadata and libraries, and whether a normal request would be served it from the render cache
Queries and logsEach query’s SQL (never its values), time and caller, and the log entries of the request

Variables are those the template received, each with its type and a preview of at most 400 characters. Anything named like a key, token, password, secret, hash, salt, nonce, session or cookie, a form’s token or build id, a long run of token characters, or a password hash is hidden as [redacted].

  • A traced render reads and writes no render cache: a hit would skip what made the part, and a write would store marks for others.
  • Placeholders and BigPipe’s streamed parts are rendered into the page for a traced request, so nothing arrives after the trace is stored. Other requests stream as before.
  • Single-directory components are marked from a Twig extension that runs after core’s own, whether they are placed from a render element or from Twig code.
  • The helper keeps the last 20 traces per user for ten minutes.

Drupal versions

The helper declares core_version_requirement: ^10.3 || ^11: any Drupal 10 from 10.3, and any Drupal 11.

Core’s classes changed shape between 10.3 and 11.4, so the trace has one class for each shape a service has taken, and puts in place the one whose signatures are exactly the running core’s, loading none to decide. When none fits, as on a release the helper does not know, core keeps its own class and the parts are found through hooks every release has.

Found through hooks, a template and its wrappers are one part, the preprocess steps are not listed, a part’s cache metadata is its own, and hooks are not timed where the module handler or theme manager is not one the helper knows. The trace’s log says so.

Every release from 10.3 to 11.4 is checked against stand-ins built from that release’s own signatures, and a page traces alike on each shape. Every file of the helper parses under PHP 8.1, Drupal 10.3’s minimum. It has not yet been seen on a real 10.x site, or on 11.0 to 11.3.

The rules a field save follows

  • The words go to the translation the page rendered and to the one item of the field holding the old words. Two items holding them are refused, never guessed between.
  • Only over what the page showed: the revision, or where the content keeps none its changed time, or else a hash of the words as rendered. Content saved since is refused.
  • Validated as Drupal’s own form for that one field would, plus the workflow’s check that you may make this change, before and after the change. A save keeps the content’s state; nothing is made a draft instead. An old problem in a field the change does not touch is noted, not refused.
  • Where the page shows more around a field’s words than the field holds (a symbol and a year added by a template, say), only the field’s own words are changed, and a change to what is added is refused as code.
  • Formatted text is changed one run of words in one stored text node, and kept only when rendering the old and new text through the item’s own format differs in those words alone. Words a filter makes and a format your user may not use are refused.

Not checked yet: what CKEditor 5, Drupal’s text editor, does to a stored text the next time it opens it.

The stored-words search on Drupal

When nothing the page offers holds the words and no template writes them, Make it real asks the helper where the content the page showed keeps them. It searches every field of that translation its other saves do not already cover: each item’s stored strings (plain words, markup, JSON read token by token, a saved list) and maps. Only the version visitors see is searched.

Never searched: references, files, numbers, dates, choices, addresses, paths and computed fields, values a contributed module keeps in its own shape (SEO tags and analyses, a view reference’s arguments, a webform’s elements, a pattern’s source, a page builder’s component tree), a paragraph’s own settings, and machine names.

It saves through the Entity API with the same gates as a field save, as a new revision with a log message, and checks just before writing that the value is still what it found. A paragraph found this way is refused: it is saved through the page that holds it instead. Undo puts the old value back as a new revision for ten minutes, while the value is still what was written.

How the search matches words is in Make real.

What has been seen

WhereWhat
In the real app on Northstar, driven by a scriptA product title made real and verified; moves; a block placement taken out after its question and put back with Undo; a link with links under it refused; the component library and its pictures; part identity; a helper another Wanigan set up
By hand on real local sitesInstalling, using and removing the helper; the trace; a field saved through its own form and put back; a block’s and a menu link’s forms; a template copied into a theme; a block and a menu link moved, a stale move refused, each undone; Go to
With stand-ins onlyFormatted text; configuration words; a menu link’s text; Layout Builder inline blocks and default layouts; paragraphs; Webform; words a template writes; the stored-words search