Attaching and creating records
attach_file_ to_ content_ element -
References an existing managed file from one content element, appended to one of its file fields (
image,assetsormedia). It creates exactly onesys_. It never uploads, moves, copies or renames a file, and never touchesfile_ reference sys_— the file has to be there already.file_ metadata Authorised on both ends: the acting user needs content-edit rights on the element's page, and the file has to lie in a permitted storage inside that user's own file mounts. Either failure is refused in the same words as an element that does not exist.
Four things worth knowing before enabling it:
- Only elements in the default language. The reference is written in the default language, so a translated element is refused rather than given a reference in a language other than its own.
- The field must accept the file. Each file field declares which
extensions it takes, and they differ —
imageaccepts fourteen,assetstwenty-seven,mediaanything. A.docxonimageis refused rather than written, because the FormEngine would reject the relation anyway. - The field is only inferred when it is unambiguous. When the element's type offers exactly one of the three, that one is used; when it offers several, the call must name the one it means. The tool does not pick.
- Calling twice attaches the file twice. That is the declared effect
(
NON_), not an accident: two references to one image are a valid thing to want, so nothing deduplicates behind the caller's back.IDEMPOTENT_ WRITE
The new reference is always appended last, and the element's own reference count is re-read afterwards. A write that left the relation inconsistent is reported as a failure and the reference is removed again.
attach_file_ to_ record -
References an existing managed file from a file field of one record in a table that has no attach tool of its own — the image of a news article (
tx_, fieldnews_ domain_ model_ news fal_) is the case it exists for (ADR-212). It creates exactly onemedia sys_, never uploads, moves or renames a file, and may attach to a hidden record: that is the draft the assistant has just created, and the tool never changes its visibility.file_ reference Rights are checked before the write:
tables_on the table (a checkmodify attach_does not make), content-edit rights on the record's page, the field-level grant for the file field, and a file inside a permitted storage and the user's own file mounts. Where the record is an inline child — a carousel item inside a content element — every record that holds it, up the chain, must pass the table, page and record-level checks as well (ADR-230); a container of the record's own table is not asked. An absent record, an unreachable file, a page the user may not edit, an owner the user may not edit and an inline child whose owner is gone are refused in the same words.file_ to_ content_ element Things worth knowing before enabling it:
- pages and tt_content are refused and point to
set_andpage_ social_ image attach_, as do system and sensitive tables.file_ to_ content_ element - The field must be a file field of the table and accept the file. The
allowedanddisallowedlists of the column apply, as narrowed by the record type'scolumns. The field is only inferred when the table has exactly one.Overrides - Title, alternative text and description belong to the reference. They
override the file's own for this one place. The copyright is a property of
the file (
sys_), not of a reference: set it withfile_ metadata update_.fal_ asset_ meta - Default language only, and calling twice attaches the file twice.
For a news draft the first attached image becomes the
og:of the article page unless a reference flagged for the preview comes first: EXT:news prints the first preview reference, otherwise the first ofimage fal_.media - pages and tt_content are refused and point to
move_content_ element -
Moves one content element to a page and a column. The element keeps its uid, its content, its language, its history and its references — only its place changes, which is what makes it the least committal write in the set.
Both ends are authorised: the acting user needs content-edit rights on the source page as well as on the target, because moving an element out of a page edits that page's content too. An
after_anchor must sit on the target page and in the same language; a wrong anchor is refused rather than silently corrected.content_ uid The destination column is always stated explicitly on the wire, so the element lands where the approval card said it would even when the anchor element sits in a column the caller did not expect.
create_content_ element_ draft -
Creates one content element on a page — the first tool that brings a record into being. Three things bound it:
- It is always hidden. There is no argument to switch that off: publishing is a separate act with a separate audience, and the approval that let the tool run approved a draft.
- The content types are read from the installation's TCA at call time,
under an exclusion rule (ADR-196). A type is offered
unless it is denied by name —
list(the legacy plugin element),html,shortcut,div, everymenu_*— or it is a plugin, known by its Extbase registration or by thepluginsorformsitem group, or its form holds a column whose payload is not prose: a FlexForm, inline children, a group or folder reference, a slug, a password. File, category and link relations do not exclude a type; the draft leaves them empty, sotextmediais offered and gets its media throughattach_. The tool description lists what the installation offers.file_ to_ content_ element - The field set is the type's own scalar columns: headline, body text,
column, language and position as arguments, and every further
input,text,select(static items),check,number,datetime,radio,colororemailcolumn of the chosen type throughfields, validated against its TCA type as the DataHandler reads it. Acheckwith several items, achecklimited bymaximumand anRecords Checked inputoremailwithevaluniquestay in the form and are refused as keys, because TYPO3 would change them in silence; so is a column the type's TCA declaresread, and a read-onlyOnly headerorbodytextrefuses the call. Identity, position, visibility, publication, audience and translation columns are refused by name; a wrong key or value refuses the whole call and names the columns the type offers. The chosen type is checked against the acting user's explicit allow-list, and the exclude-field grants per column — the tool's own columns included — before the write; adatetimeis handed over as the integer both supported cores store. The page's TSconfig narrows all of this per page, as it narrows the backend form:TCEFORM.andtt_ content. CType. keep Items remove;Items disabledandconfig.on aread Only fieldscolumn, onbodytextand onheader— a hidden or read-only header refuses the call, since the header is required, and like the backend form the tool does not readconfig.for aread Only radiocolumn; andkeepandItems removeon a select column inItems fields, oncolfor thePos columnargument and onsys_for thelanguage_ uid languageargument — each also undertypes.<CType>— are honoured, and the refusal names the rule; a refused content type is answered with the types the page does offer.addis not read, and a column that isItems readin the TCA stays refused even where a page setsOnly config.. This is still not a generic record API: the table is fixed and a relation is never an argument.read Only = 0
In a language other than the default one the element is created standalone, without a translation parent. That is refused on a page which already holds connected translations in that language (ADR-193): a standalone element beside them is what the page module reports as Inconsistent content detected. The refusal sends the model to the default language and to
create_. A page whose TSconfig setstranslation_ draft mod.is exempt, as it is from core's warning.web_ layout. allow Inconsistent Language Handling bodytextis refused for a type whose form does not show it, such asheader. Otherwise it reaches the DataHandler and its RTE transformation exactly as an editor's input does. It is bounded in length and not otherwise filtered — an editor may write the same markup by hand, and a tool enforcing a stricter rule than the CMS would be enforcing a rule that does not exist. create_page_ draft -
Creates one standard page under a parent page — the first tool that brings a page into being (ADR-180). It is bounded the same way the element draft is, and a little further:
- It is always hidden, with no argument to switch that off. Core's own
default for a new page is hidden as well; the tool does not rely on it —
an installation that sets
TCAdefaults.gets the same read-back, and a page that came out visible is deleted again.pages. hidden = 0 - It is always a standard page in the default language. Shortcuts, mount points, links, folders and translations are out of reach; a translation has its own tool.
- The field set is fixed: title, navigation title, position (
parentand an optionalafter_that must be a subpage of the same parent). The URL segment is generated by the DataHandler from the title.page_ uid
Authorised by the acting user's new page permission on the parent; the DataHandler then enforces
tables_, the page-type grant and the field-level grants on top.modify It creates the page and nothing on it — one record per call, as for every writer. The success message hands the model the new uid and names
create_as the tool to put text on it, so "a page with an introduction" is two calls and two approvals, each showing one record.content_ element_ draft - It is always hidden, with no argument to switch that off. Core's own
default for a new page is hidden as well; the tool does not rely on it —
an installation that sets
create_translation_ draft -
Translates one page or content element into another language by running core's own
localizecommand, so connected-mode translations, inline children and every localisation hook behave exactly as they do in the backend.The result is hidden, which is the part core does not do:
localizecopies the source's visibility, so a translation of a live page would go live the moment it was created.An existing translation stops the call and is named in the refusal. The
overwriteargument is the only way past it: it deletes that translation first — recoverably (deleted = 1) and insys_— and the approval card says so on its own line. A language the record's site does not define is refused before anything is created.log The text is then machine-translated (ADR-209): every text column of the record's type that holds text in the source — headline, subheader, body, page title, navigation title, description and the like, but not the page's author — is translated from the source record and written into the translation. Rich text is sent as HTML, so its markup survives. A translation longer than a column's maximum length is cut to it, and the result says so. The
translatorargument choosesdeeplorllm(the default); a translator the installation has not configured is refused. The glossary of the record's site for the language pair applies (see Glossaries). The approval card names the translator, the fields, fields the user may not edit, and whether the site keeps a glossary for the pair.If a translation fails, comes back empty or is cut off at the translator's output limit, nothing is written: the draft keeps the copied source text and the result says The text was NOT machine-translated with the reason. If the write itself fails, the result names which fields hold the translation and which still hold the source text.
Identical translations are answered from a cache for a day. A cached answer does not reach the translator, so it passes no budget check and records no usage. Saving or deleting a glossary, an LLM configuration, a model, a provider, a skill or a prompt snippet empties that cache.
create_record_ draft -
Creates one record in a TCA table that has no dedicated writer — the fallback for extension tables such as a news record (ADR-197). It serves a table by exclusion:
pagesandtt_have writers of their own and are refused by name;content sys_*tables, the tables no tool may read (be_,users sys_, the nr_llm and nr_vault tables …) and tables declaredlog admin,Only hideorTable readare refused as well.Only - A table another registered creator declares through
Recordis refused and the tool named — read at call time, so an extension that ships its own creator withdraws the fallback the day it is installed. The builtin creators declareCreator Interface:: get Created Tables () tt_(content create_),content_ element_ draft pages(create_) and both (page_ draft create_). A declaration that cannot be read refuses the call and names the tool.translation_ draft - The extension configuration
tools.(comma-separated table names, empty by default) excludes further tables on one installation. It can only narrow the list, never widen it, and a configuration that cannot be read refuses every table.create Record Draft. denied Tables - A table without a "disabled" enable column is refused, because nothing this extension writes may be visible before a human unhides it.
Only scalar columns can be set —
input,text,number,email,color,datetime(as a timestamp),check,radioandselectwith static items — and only those the record type's form shows as writable on that page: a column the TCA declaresreadis refused unless page TSconfigOnly TCEFORM.<table>.<column>.lifts it, as it does in the form (aconfig. read Only = 0 radioexcepted, whosereadthe form does not let page TSconfig change). Relations, files, FlexForms, links and slugs are not arguments;Only hidden,uid,pid, the language, timing, ownership and versioning columns are refused by name. Values are checked against the record type's TCA — itscolumnsincluded — before anything is written: the items of a select,Overrides maxandrange, 0/1 for a check, a valid address for an email. The record type is the one the DataHandler gives the record — the call's value for the type column, elseTCAdefaultsfrom the page's TSconfig, then from the acting user's, else the column's default — and the tool writes it explicitly where the acting user may write the type column, leaving it to the DataHandler otherwise; aTCAdefaultsvalue that names no record type of the table is refused. Every column the record type marks required must be given. A value the DataHandler would rewrite is refused rather than written: a column with anevalthe DataHandler acts on (upper,alphanum,unique,unique, an extension's registered evaluation …; a token it ignores is ignored here too), an eight-digit colour on a column withoutIn Pid opacity, a text shorter than itsmin, a decimal with more than two decimal places (TYPO3 stores two), a decimal the range check would clamp. So is what the page's TSconfig takes out of the backend form: a columnTCEFORM.<table>.<column>.hides, a select valuedisabled keeporItems removefilters out, a columnItems TCEFORM.<table>.<column>.makes read-only, and a record type its type field does not offer on that page — the refusal names the rule.config. read Only The record is always hidden and always in the default language. Authorised by the acting user's
tables_grant, the content-edit permission on the page or folder, and the field-level grants for every column the call sets — asked before the write, because the DataHandler drops such a column in silence. What TYPO3 still rewrites — a hook of the installation, a grant the pre-check does not model — is read back afterwards, the default language included, and the record type unless it is core's fallback type and the tool could not write it; a record that does not carry what was approved is deleted again and the columns are named.modify The approval card names each column with the record type's TCA label — a showitem
field;Label, else acolumnslabel, else the column's own — in English, never in the viewer's language, because the card is compared byte for byte when the run resumes:Overrides published_. A page TSconfig label override (at (Published at): "2026- 09- 10T10: 00: 00+00: 00" TCEFORM.<table>.<column>.) is not applied, although the backend form shows it: the card must not depend on the page or on the viewer's language.label It declares no editor action — it has no record an editor would select — so it is reached through the assistant only, never from a record's context menu.