Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

The subitems list: Table options and its columns

Read this page if your editors use the sub items list in the admin, if you override children_detailed.tpl or its JavaScript, or if you want to add a column of your own. In Exponential 6.0.15 the Table options of the…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/bc/6.0/subitems-table-options.md

On this page

The subitems list: Table options and its columns

Read this page if your editors use the sub items list in the admin, if you override children_detailed.tpl or its JavaScript, or if you want to add a column of your own. In Exponential 6.0.15 the Table options of the list under every node (content/view/full/<node id>) offers a catalogue of more than a hundred columns instead of 15 fixed ones, grouped, sortable on the server, reorderable, with presets and CSV export. A site developer adds a column with a few lines of INI and a PHP function or a template.

Everything a column shows is computed on the server, only for the columns the user made visible and only for the rows of the page on screen. A column the user may not see (its Policy[]) is not offered, not computed and not sent.

In short

What changedNew column catalogue settings/subitemscolumns.ini (129 columns), new settings in settings/subitems.ini (PageSizes[], CSVLimit, ...), server functions behind the list, the user's choice stored on the server per part of the admin. The old eZSubitemColumns cookie is taken over once.
Who is affectedOverrides of children_detailed.tpl in admin or admin4, and of the list's JavaScript: they keep the classic 15 columns. Installations whose ezjscore.ini lacks the new server functions fall back to the classic list too.
How to checkphp vendor/bin/phpunit tests/tests/kernel/classes/subitems/
How to fixMerge your overrides with the shipped templates; keep ezjscore.ini current. To add a column, follow Adding a column in 3 minutes.

What users see

Table options (the button above the list) has:

  • Number of items per page: 10, 25, 50, 100 (subitems.ini [SubitemsSettings] PageSizes[]), or a custom number.
  • Find a column: a filter box; type part of a name ("alias", "count") and only the matching columns stay in the list.
  • The columns by group: Basic, Node, Object, Version, Location, URLs, SEO, Dates, People, Relations, Translations, Workflow, Users, Media, Technical, Custom, and one group "Attributes: <class>" per class among the children. A checkbox per column; the column's description is its tooltip.
  • Order of the visible columns: drag a column to move it, or use its arrow buttons.
  • Column presets: choose one (SEO, Editorial, Technical, Translations ship with the system), Save current as... to keep the current columns under a name of your own, Delete preset for your own.
  • Export CSV: downloads every child (up to CSVLimit) with the visible columns, in their order.

In the table itself, a click on a sortable column's header sorts the list by it, on the server (so the order is right across pages). A cell of a column marked Copy=true (IDs, paths, URLs, the page title ...) copies its value on a click and says "Copied".

The choice is saved for the user, per part of the admin (the content tree, the media library and the users keep their own), on the server: it follows the user to every browser. The columns chosen earlier in the eZSubitemColumns cookie are taken over the first time.

The list works this way in every admin design: admin and admin4 have their own children_detailed.tpl, the other admin designs (admin2, admin3, sevenx_site_admin) use the one of the design they fall back on. Without the server functions (an old ezjscore.ini) it falls back to the classic 15 columns.

The column catalogue

129 columns ship in settings/subitemscolumns.ini; on top of them come the automatic attribute columns (below). "Sort" names the field the list sorts by when the header is clicked (empty: not sortable); "Policy" the functions a user needs to be offered the column at all. "Kind" is how the value is made: built-in (rendered by the list from the node, as before), a class and its Field=, a Handler or a Template.

GroupColumns
Basic5 (built-in)
Node16 (2 built-in)
Object14 (3 built-in)
Version7
Location5
URLs10
SEO5
Dates10 (2 built-in)
People5 (1 built-in)
Relations6
Translations6 (1 built-in)
Workflow12 (1 built-in)
Users9
Media12
Technical4
Custom3

Basic (5)

KeyNameKindWhat it showsSortPolicy
thumbnailThumbnailbuilt-inA small preview of the item's image, or its class icon.
nameNamebuilt-inThe item's name, linked to its page in the admin.name
visibilityVisibilitybuilt-inVisible, Hidden or Hidden by superior.visibility
typeTypebuilt-inThe name of the item's content class.class_name
priorityPrioritybuilt-inThe priority within the parent; editable in place when the parent sorts by priority.priority

Node (16)

KeyNameKindWhat it showsSortPolicy
nodeidNode IDbuilt-inThe ID of the location (node).node_id
noderemoteidNode remote IDbuilt-inThe remote ID of the location, stable across installations.
parentnodeidParent node IDexpSubitemsNodeColumn parent_node_idThe node ID of the item's parent location.
depthDepthexpSubitemsNodeColumn depthHow deep the location is in the tree (the content root is 1).depth
pathstringPath stringexpSubitemsNodeColumn path_stringThe node IDs from the top of the tree down to the item: /1/2/89/120/.path
pathidentificationPath identification stringexpSubitemsNodeColumn path_identificationThe location's path as identifiers (ezcontentobject_tree.path_identification_string).path_string
mainnodeidMain node IDexpSubitemsNodeColumn main_node_idThe node ID of the object's main location (the same as Node ID when this is it).
childsortfieldChildren sorted byexpSubitemsNodeColumn sort_fieldHow the item sorts its own children: published, name, priority, modified ...
childsortorderChildren sort orderexpSubitemsNodeColumn sort_orderAscending or descending, for the item's own children.
hiddenHiddenexpSubitemsNodeColumn is_hiddenHidden by an editor: the item itself was hidden (not one of its parents).
invisibleInvisibleexpSubitemsNodeColumn is_invisibleNot shown to visitors: hidden itself or below a hidden location.visibility
iscontainerContainerexpSubitemsNodeColumn is_containerWhether the item's class can have children.
childrencountNode children countexpSubitemsNodeColumn children_countThe direct children you may read. One count query per row.
subtreecountSubtree sizeexpSubitemsNodeColumn subtree_countEvery item below, all depths, that you may read. One count query per row over the whole subtree: slower for big trees.
childclassesChild classesexpSubitemsNodeColumn child_classesThe classes of the direct children with their numbers, most frequent first. One grouped query per row; counts every child.
newestchildnameNewest childexpSubitemsNodeColumn newest_child_nameThe name of the most recently published child you may read. One limited query per row.

Object (14)

KeyNameKindWhat it showsSortPolicy
sectionSectionbuilt-inThe name of the item's section.section
objectidObject IDbuilt-inThe ID of the content object.contentobject_id
objectremoteidObject remote IDbuilt-inThe remote ID of the content object, stable across installations.
classidentifierClass identifierexpSubitemsObjectColumn class_identifierThe identifier of the item's class, as templates and fetches use it.class_identifier
classidClass IDexpSubitemsObjectColumn class_idThe ID of the item's class.
classgroupsClass groupsexpSubitemsObjectColumn class_groupsThe class groups the item's class belongs to (one query per class, not per row).
sectionidentifierSection identifierexpSubitemsObjectColumn section_identifierThe identifier of the item's section (sorting orders by section ID).section
sectionidSection IDexpSubitemsObjectColumn section_idThe ID of the item's section.section
wordcountWord countexpSubitemsObjectColumn word_countWords in the main text: the first of body, description, intro, short_description, else the first rich text, XML or text block with content. Reads the data map.
textlengthText lengthexpSubitemsObjectColumn text_lengthCharacters in the main text, markup left out. Reads the data map.
readingtimeReading timeexpSubitemsReadingTimeColumnMinutes a reader needs for the main text (see Word count), at WordsPerMinute words a minute. Reads the data map.
namelengthName lengthexpSubitemsObjectColumn name_lengthCharacters in the item's name.
ratingRatingexpSubitemsRelationColumn ratingThe average star rating (needs the ezstarrating extension); empty when never rated.
ratingcountRatingsexpSubitemsRelationColumn rating_countHow many star ratings were given (needs the ezstarrating extension).

Version (7)

KeyNameKindWhat it showsSortPolicy
versionObject versionexpSubitemsVersionColumn versionThe number of the current (published) version.
versioncountVersionsexpSubitemsVersionColumn version_countEvery stored version: published, archived, drafts and the rest.
draftcountDraftsexpSubitemsVersionColumn draft_countOpen drafts that are not published yet.
draftauthorsDraft authorsexpSubitemsVersionColumn draft_authorsWho has an open draft of the item.
latestdraftLatest draftexpSubitemsVersionColumn latest_draftWhen the most recent open draft was last changed.
archivedcountArchived versionsexpSubitemsVersionColumn archived_countEarlier versions kept in the history.
versioncreatedVersion createdexpSubitemsVersionColumn version_createdWhen the current version was started (Modified says when it was published).

Location (5)

KeyNameKindWhat it showsSortPolicy
parentnameParentexpSubitemsNodeColumn parent_nameThe name of the parent location (fetched once per page).
ismainMain locationexpSubitemsNodeColumn is_mainWhether this is the object's main location.
locationcountLocationsexpSubitemsURLColumn location_countHow many locations the object has. One query per row.
otherlocationsOther locationsexpSubitemsURLColumn other_locationsThe URL aliases of the object's other locations.
mainlocationMain location pathexpSubitemsURLColumn main_locationThe URL alias of the main location, when this row is not it.

URLs (10)

KeyNameKindWhat it showsSortPolicy
urlaliasURL aliasexpSubitemsURLColumn url_aliasThe item's URL alias as the admin uses it (the path from the content root); / for the node at the site root.path_string
allaliasesAll URL aliasesexpSubitemsURLColumn all_aliasesEvery own URL alias of the item, in all its languages (/ is the site root). Shares the alias query with the other alias columns.
systemurlSystem URLexpSubitemsURLColumn system_urlcontent/view/full/<node id>: the address that always works, whatever the aliases.
publicpathPublic pathexpSubitemsURLColumn public_pathThe path visitors use on the public siteaccess: the URL alias without that siteaccess's PathPrefix.
publicurlPublic URLexpSubitemsURLColumn public_urlThe full address on the public site: the public siteaccess's SiteURL and the public path.
urlslugURL slugexpSubitemsURLColumn url_slugThe last element of the URL alias.
aliascountURL aliasesexpSubitemsURLColumn alias_countThe item's own URL aliases, one per translation normally. One query per row, shared with the other alias columns.
customaliasesCustom URL aliasesexpSubitemsURLColumn custom_aliasesThe extra aliases made in Manage URL aliases.
customaliascountCustom URL alias countexpSubitemsURLColumn custom_alias_countHow many extra aliases were made in Manage URL aliases.
historycountOld URLsexpSubitemsURLColumn history_countFormer addresses (after renames and moves) that still redirect to the item.

SEO (5)

KeyNameKindWhat it showsSortPolicy
pagetitlePage title in the browserexpSubitemsSEOColumn page_titleThe public site's title for the item's page, worked out as its pagelayout does, without rendering the page.
titlelengthPage title lengthexpSubitemsSEOColumn title_lengthCharacters in the page title; search engines show about 60.
metatitleMeta titleexpSubitemsSEOColumn meta_titleThe title set in the item's metadata attribute (xrowmetadata); empty when none.
metadescriptionMeta descriptionexpSubitemsSEOColumn meta_descriptionThe description set in the item's metadata attribute (xrowmetadata).
metakeywordsMeta keywordsexpSubitemsSEOColumn meta_keywordsThe keywords set in the item's metadata attribute (xrowmetadata).

Dates (10)

KeyNameKindWhat it showsSortPolicy
modifiedModifiedbuilt-inWhen the current version was published.modified
publishedPublishedbuilt-inWhen the item was first published.published
modifiedsubnodeSubtree modifiedexpSubitemsNodeColumn modified_subnodeWhen anything in the item's subtree last changed.modified_subnode
publishedagePublished (age)expSubitemsDateColumn published_ageHow long ago the item was first published: 3 days ago.published
modifiedageModified (age)expSubitemsDateColumn modified_ageHow long ago the current version was published.modified
dayssincepublishedDays since publishedexpSubitemsDateColumn days_since_publishedWhole days since the item was first published.published
dayssincemodifiedDays since modifiedexpSubitemsDateColumn days_since_modifiedWhole days since the current version was published.modified
publishedisoPublished (ISO 8601)expSubitemsDateColumn published_isoThe publishing time as 2026-10-02T09:30:00+00:00, for copying.published
modifiedisoModified (ISO 8601)expSubitemsDateColumn modified_isoThe modification time as 2026-10-02T09:30:00+00:00, for copying.modified
newestchildNewest child publishedexpSubitemsNodeColumn newest_childWhen the most recently published child you may read was published. One limited query per row.

People (5)

KeyNameKindWhat it showsSortPolicy
modifierModifierbuilt-inWho published the current version.
ownerOwnerexpSubitemsObjectColumn ownerThe user who created the object (its owner).
owneridOwner IDexpSubitemsObjectColumn owner_idThe object ID of the owner.
initialcreatorFirst authorexpSubitemsVersionColumn initial_creatorWho wrote the first version still stored.
contributorsContributorsexpSubitemsVersionColumn contributorsEveryone who wrote a version, in the order of their first version.

Relations (6)

KeyNameKindWhat it showsSortPolicy
relatedcountRelated objectsexpSubitemsRelationColumn related_countObjects the item relates to (all relation types). One count query per row.
relatednamesRelated object namesexpSubitemsRelationColumn related_namesThe names of the first related objects you may read, by name.
reverserelatedcountReverse related objectsexpSubitemsRelationColumn reverse_related_countObjects that relate to the item: what would point nowhere if it were removed. One count query per row.
reverserelatednamesReverse related namesexpSubitemsRelationColumn reverse_related_namesThe names of the first objects that relate to the item and that you may read.
tagsTagsexpSubitemsRelationColumn tagsThe tags on the item (needs the eztags extension and a tags attribute).
tagcountTag countexpSubitemsRelationColumn tag_countHow many tags the item has (needs the eztags extension).

Translations (6)

KeyNameKindWhat it showsSortPolicy
translationsTranslationsbuilt-inThe flags of the languages the item is translated into.
initiallanguageInitial languageexpSubitemsObjectColumn initial_languageThe language the item was first written in.
languagecountLanguagesexpSubitemsObjectColumn language_countHow many languages the item is translated into.
languagecodesLanguage codesexpSubitemsObjectColumn language_codesThe locales of the translations, e.g. eng-GB, ger-DE.
missingtranslationsMissing translationsexpSubitemsObjectColumn missing_translationsThe installation's languages the item is not translated into.
alwaysavailableAlways availableexpSubitemsObjectColumn always_availableShown in every language, also those it has no translation in.

Workflow (12)

KeyNameKindWhat it showsSortPolicy
objectstateObject statebuilt-inThe item's object states, as group/state identifiers.
statusbadgeStatusTemplateOne badge: Visible, Hidden, Hidden by a parent or Locked (a template column).
lockedLockedexpSubitemsObjectColumn lockedIn the "locked" state of the Lock (ez_lock) state group.
pendingcountPending versionsexpSubitemsVersionColumn pending_countVersions waiting in a workflow, an approval for instance.
rejectedcountRejected versionsexpSubitemsVersionColumn rejected_countVersions an approver rejected.
workflowprocessesWorkflow processesexpSubitemsVersionColumn workflow_processesWorkflow processes running for the item (an approval, a delayed publication). One count query per row.
caneditYou can editexpSubitemsPermissionColumn can_editWhether you may edit the item.
canremoveYou can removeexpSubitemsPermissionColumn can_removeWhether you may remove the item.
canmoveYou can moveexpSubitemsPermissionColumn can_moveWhether you may move the item.
canhideYou can hideexpSubitemsPermissionColumn can_hideWhether you may hide and reveal the item.
cantranslateYou can translateexpSubitemsPermissionColumn can_translateWhether you may translate the item.
cancreateYou can create belowexpSubitemsPermissionColumn can_createWhether you may create content below the item; empty when it is not a container.

Users (9)

KeyNameKindWhat it showsSortPolicy
userloginLoginexpSubitemsUserColumn loginThe user's login name.role/read
useremailE-mailexpSubitemsUserColumn emailThe user's e-mail address. Only for users who may assign roles.role/assign
userenabledAccount enabledexpSubitemsUserColumn enabledWhether the account may log in.role/read
userlockedLocked outexpSubitemsUserColumn lockedLocked out after too many failed logins (site.ini [UserSettings] MaxNumberOfFailedLogin).role/read
userlastvisitLast visitexpSubitemsUserColumn last_visitWhen the user's last visit began; empty when they never logged in.role/read
userlogincountLoginsexpSubitemsUserColumn login_countHow many times the user has logged in.role/read
userfailedloginsFailed loginsexpSubitemsUserColumn failed_loginsFailed login attempts since the last successful one.role/assign
userrolesRolesexpSubitemsUserColumn rolesThe roles that apply to the user, directly or through their groups. Two queries per row.role/read
userrolecountRole countexpSubitemsUserColumn role_countHow many roles apply to the user.role/read

Media (12)

KeyNameKindWhat it showsSortPolicy
hasimageHas imageexpSubitemsMediaColumn has_imageWhether the item has an image; empty when its class has no image attribute.
imagecountImagesexpSubitemsMediaColumn image_countImage attributes that hold an image.
imagedimensionsImage dimensionsexpSubitemsMediaColumn image_dimensionsWidth x height of the original image, in pixels.
imagewidthImage widthexpSubitemsMediaColumn image_widthThe width of the original image, in pixels.
imageheightImage heightexpSubitemsMediaColumn image_heightThe height of the original image, in pixels.
imagesizeImage file sizeexpSubitemsMediaColumn image_sizeThe size of the original image file (in bytes in the CSV).
imagemimeImage typeexpSubitemsMediaColumn image_mimeThe MIME type of the original image.
imagealtImage alternative textexpSubitemsMediaColumn image_altThe image's alternative text; empty when it has none, which is worth fixing.
filenameFile nameexpSubitemsMediaColumn file_nameThe name the file (binary file or media) was uploaded with.
filesizeFile sizeexpSubitemsMediaColumn file_sizeThe size of the stored file (in bytes in the CSV).
filemimeFile typeexpSubitemsMediaColumn file_mimeThe MIME type of the file.
filedownloadsDownloadsexpSubitemsMediaColumn file_downloadsHow often the file was downloaded through content/download.

Technical (4)

KeyNameKindWhat it showsSortPolicy
searchwordsSearch index wordsexpSubitemsPermissionColumn search_wordsWord positions the built-in search engine indexed for the item (0: not indexed). One count query per row; empty with another search engine.
viewcountView countexpSubitemsNodeColumn view_countViews counted in ezview_counter (filled by the updateviewcount cronjob); empty when never counted.
languagemaskLanguage maskexpSubitemsObjectColumn language_maskThe object's language bit mask (bit 0: always available).
attributecountAttributesexpSubitemsObjectColumn attribute_countAttributes of the current version in the shown language. Reads the data map.

Custom (3)

KeyNameKindWhat it showsSortPolicy
teaserTeaserTemplateThe first words of the intro, description or body (a template column).
editlinkEdit linkHandlerThe address of the item's edit page, when you may edit it (a Handler column).
daysonlineDays onlineHandlerWhole days since the item was first published (a Handler column).published

How some columns work it out

  • Page title in the browser (pagetitle) is the <title> the public site prints for the item's page, worked out from the node and the public siteaccess's settings, without rendering the page. The public siteaccess is SiteAccess= in the block, else site.ini [SiteSettings] DefaultAccess (on the reference installation: site). TitleFormat= picks the rule of the design that siteaccess uses:

    • name (the default; the media design, extension/sevenx_themes_media/design/media/templates/pagelayout/head/title.tpl): <page title> - <SiteName>, where the page title is the meta title of the item's xrowmetadata attribute when it has one, else the item's name; the page title alone when it equals SiteName. So on the reference installation the media root is "Media - Fit & Healthy", and the front page node "Fit & Healthy" is just "Fit & Healthy".
    • path (design/standard and ezwebin page_head.tpl): the names of the item and its ancestors, the item first, joined by " / ", then " - <SiteName>": "Banners / Media - Bold Agency" (the example under "The shipped families").

    SiteName is the public siteaccess's [SiteSettings] SiteName; names are taken in its first SiteLanguageList[] language when the item has it. The value is the plain text (with &, not &amp;), as the browser shows it. A meta title is used as it is stored; the xrowmetadata metadata() operator leaves [name] style placeholders in place, and so does the column.

  • URL alias (urlalias) is the alias the admin uses (url_alias of the node). The kernel answers an empty alias in two cases, and the column resolves both from the alias table instead of showing an empty cell: the node that owns the root element of ezurlalias_ml (the row with parent 0 and empty text) is the page at the site root and shows /; the content root ([NodeSettings] RootNode), whose pathWithNames() is always empty, shows its own alias when the root element belongs to another node. On the reference installation the root element belongs to node 89 ("Fit & Healthy", the front page), which also has the named alias fit-healthy its children hang below, and node 2 is reached at websites. All URL aliases (allaliases) lists every own alias of the item.

  • Public path / Public URL take the public siteaccess's PathPrefix off the alias (unless PathPrefixExclude[] keeps it, as urlAlias() does) and put its SiteURL in front, with Scheme=https unless SiteURL has a scheme.

  • Hidden is the item hidden by an editor; Invisible is "not shown to visitors", hidden itself or below a hidden node. They differ for everything below a hidden node.

  • Node children count counts the children the current user may read; Child classes counts every child per class (numbers only, no names).

  • Word count, Text length and Reading time read the main text: the first of body, description, intro, short_description (or Attributes[] in the block) that is a rich text, XML or text block with content, else the first such attribute at all; markup is left out.

  • Users columns are empty for anything that is not a user account.

  • Rating, Tags need the ezstarrating and eztags extensions and an attribute of that kind; without them they are empty, never an error.

Every column gives an empty cell (null) when it does not apply to an item's class, and never stops the list: a column that fails gives an empty cell and a debug warning.

Adding a column in 3 minutes

A column is one [Column_<key>] block. Put it in settings/override/subitemscolumns.ini.append.php, or better in an extension: extension/<yours>/settings/subitemscolumns.ini.append.php (with the extension listed in ActiveExtensions[]). The key is lowercase letters, digits and _. Clear the INI cache afterwards (php bin/php/ezcache.php --clear-tag=ini); reload the PHP-FPM that serves the admin when a PHP class was added (and regenerate the autoloads). A new template also needs the template override cache cleared (--clear-id=template-override), or the cell stays empty.

The three examples below are the ones tests/tests/kernel/classes/subitems/columns/fixtures/subitemscolumns.ini.append.php holds; expSubitemsGuideExamplesTest loads that file into a registry and computes the columns as the rows server function does.

1. A Handler: one function

[Column_mydaysonline]
Name=Days online
Group=Custom
Type=number
Handler=expSubitemsColumnHandlers::daysOnline
SortField=published
Align=right
Order=5000
Description=Whole days since the item was first published.
class expSubitemsColumnHandlers
{
    public static function daysOnline( eZContentObjectTreeNode $node, array $settings, expSubitemsColumn $column )
    {
        $object = $node->attribute( 'object' );
        $published = $object instanceof eZContentObject ? (int)$object->attribute( 'published' ) : 0;
        return $published > 0 ? expSubitemsColumn::days( $published ) : null;
    }
}

The function gets the row's node, the block as an array and the column object, and returns the value: null, a scalar, or a list of scalars. Type= decides how the cell and the CSV show it (a number here). SortField=published makes the header sort the list by publishing date. The shipped kernel/classes/subitems/columns/expsubitemscolumnhandlers.php has this one and editLink.

2. A Class: a column of your own

[Column_myreadingtime]
Name=Reading time
Group=Custom
Type=number
Class=expSubitemsReadingTimeColumn
WordsPerMinute=250
Align=right
Order=5010
Description=Minutes a reader needs for the main text.
class expSubitemsReadingTimeColumn extends expSubitemsColumn
{
    public function value( eZContentObjectTreeNode $node )
    {
        $count = $this->wordCount()->value( $node );
        if ( !$count )
            return null;
        $perMinute = max( 1, (int)$this->setting( 'WordsPerMinute', 200 ) );
        return max( 1, (int)ceil( $count / $perMinute ) );
    }

    public function html( eZContentObjectTreeNode $node, $value )
    {
        return $value === null ? '' : self::escape( $value . ' ' . ezpI18n::tr( 'design/admin/node/view/full', 'min' ) );
    }

    public function prefetch( array $nodes )
    {
        $this->wordCount()->prefetch( $nodes );
    }

    protected function wordCount()
    {
        return new expSubitemsObjectColumn( $this->key, array( 'Field' => 'word_count' ) + $this->settings );
    }
}

A class extends expSubitemsColumn and implements value(); it may override html() (the cell; escape everything with self::escape()), text() (the CSV), sortBy(), isAvailable() and prefetch() (see Performance). It reads its own settings with $this->setting( 'Name', $default ), so one class can serve several blocks. The base class has the formatting every column shares, for use in value() and html(): escape(), oneLine(), markupToText(), linkHtml(), formatDate(), formatAge() ("3 days ago"), days(), formatBytes() ("245 kB"), and memo( $bucket, $key, $compute ) for a lookup done once per request. This is the shipped readingtime column (kernel/classes/subitems/columns/expsubitemsreadingtimecolumn.php).

3. A Template: markup without PHP

[Column_mystatus]
Name=Status
Group=Custom
Type=html
Template=design:subitems/columns/statusbadge.tpl
Order=5020
Description=What visitors see of the item.
{def $exp_badge = 'visible'}
{if $node.is_hidden}{set $exp_badge = 'hidden'}
{elseif $node.is_invisible}{set $exp_badge = 'invisible'}
{elseif $node.object.state_identifier_array|contains( 'ez_lock/locked' )}{set $exp_badge = 'locked'}{/if}
{switch match=$exp_badge}
{case match='hidden'}<span class="exp-subitems-badge exp-subitems-badge-hidden">{'Hidden'|i18n( 'design/admin/node/view/full' )}</span>{/case}
...
{case}<span class="exp-subitems-badge exp-subitems-badge-visible">{'Visible'|i18n( 'design/admin/node/view/full' )}</span>{/case}
{/switch}
{undef $exp_badge}

The template gets $node (the row), $column (the block as a hash: $column.Length, $column.Attributes) and $key. Its output is the cell; its text without tags ("Visible") is the value and the CSV text. Escape what you print (|wash). The shipped design/standard/templates/subitems/columns/statusbadge.tpl and teaser.tpl are both examples; teaser.tpl shows reading block settings and an XML text block.

The shipped families

Most shipped columns are one class per family with Field= choosing the column, so a block of your own can reuse them with other settings (another SiteAccess= for the page title, Limit= for relation names, Attributes[] for the main text or the image):

ClassFields
expSubitemsNodeColumnparent_node_id, parent_name, depth, path_string, path_identification, main_node_id, is_main, sort_field, sort_order, is_hidden, is_invisible, is_container, children_count, subtree_count, child_classes, newest_child, newest_child_name, modified_subnode, view_count
expSubitemsObjectColumnclass_identifier, class_id, class_groups, section_identifier, section_id, owner, owner_id, initial_language, language_count, language_codes, missing_translations, always_available, language_mask, state_identifiers, locked, word_count, text_length, name_length, attribute_count
expSubitemsVersionColumnversion, version_count, draft_count, draft_authors, latest_draft, archived_count, pending_count, rejected_count, initial_creator, contributors, version_created, workflow_processes
expSubitemsURLColumnurl_alias, all_aliases, system_url, public_path, public_url, url_slug, alias_count, custom_aliases, custom_alias_count, history_count, location_count, other_locations, main_location
expSubitemsSEOColumnpage_title, title_length, meta_title, meta_description, meta_keywords
expSubitemsDateColumnpublished_age, modified_age, days_since_published, days_since_modified, published_iso, modified_iso
expSubitemsUserColumnlogin, email, enabled, locked, last_visit, login_count, failed_logins, roles, role_count
expSubitemsMediaColumnhas_image, image_count, image_dimensions, image_width, image_height, image_size, image_mime, image_alt, file_name, file_size, file_mime, file_downloads
expSubitemsRelationColumnrelated_count, related_names, reverse_related_count, reverse_related_names, tags, tag_count, rating, rating_count
expSubitemsPermissionColumncan_edit, can_remove, can_move, can_hide, can_translate, can_create, search_words

For example, the title of the bold siteaccess, by the path rule (design/standard style):

[Column_pagetitle_bold]
Name=Page title (bold)
Group=SEO
Type=text
Class=expSubitemsSEOColumn
Field=page_title
SiteAccess=bold
TitleFormat=path
Copy=true
Order=701
Description=The <title> of the bold siteaccess.

On the reference installation the media root's first child then shows "Banners / Media - Bold Agency". A SiteAccess= that is not in AvailableSiteAccessList[] gives an empty cell.

Automatic attribute columns

With subitems.ini [SubitemsSettings] AttributeColumns=enabled, Table options also offers one column per attribute of every class among the parent's children, in a group "Attributes: <class name>", key attr:<class identifier>/<attribute identifier> (one query finds the classes). The value is the attribute's title, else its text without tags (at most 300 characters); the column sorts when the datatype has a sort key, and sorting by it limits the list to that class (subTree's attribute sort leaves the other classes out; the count stays right). AttributeColumnsExcludedDataTypes[] keeps datatypes out (ezuser by default: its text holds the password hash), and AttributeColumnsDataTypePolicy[<datatype>]=module/function gives a datatype's columns a policy.

Policies

Policy[]=module/function entries in a block must all be granted (any limitation counts as granted) or the column does not exist for that user: not in Table options, not computed, not in the rows or the CSV, and a saved choice or preset that names it simply leaves it out. Several entries can also be written in one line separated by ;. The rows themselves always respect content/read: the list and the CSV only show children the user may read, and the rows function requires read access to the parent.

The shipped policies: the Users group needs role/read (the people who see the role setup), and E-mail and Failed logins need role/assign. Columns that list names of other objects (related objects) leave out those the user may not read.

Defaults per subtree and class

What a user sees before saving a choice of their own comes from subitems.ini: the first [Defaults_<id>] block whose Subtree[] holds the parent or one of its ancestors, or whose ParentClassIdentifiers[] holds the parent's class, wins, in file order; else DefaultColumns[]. The shipped blocks keep the list's former defaults for the media library (thumbnail;name;visibility;type) and the users tree.

[Defaults_fitness]
Subtree[]
Subtree[]=92
ParentClassIdentifiers[]
ParentClassIdentifiers[]=ng_blog
Columns[]
Columns[]=name
Columns[]=published
Columns[]=publishedage
Columns[]=pagetitle

On the reference installation this gives name, published, publishedage, pagetitle under "Fitness" (node 92) and under every node below it. Blocks added by an override file come after the shipped ones, so to change the media library's or the users' defaults, override Columns[] of [Defaults_media] / [Defaults_users] instead of adding a block for the same place.

Presets

[Preset_<id>] blocks in subitems.ini (id: a-z, 0-9, _, -) are offered to everybody: Name= and Columns[] in order. Shipped: seo, editorial, technical, translations. Users save their own next to them ("Save current as..."), at most 20, and cannot take an INI preset's id. A preset's columns the user may not see are left out for that user.

INI reference

settings/subitemscolumns.ini

SettingMeaning
[Column_<key>]one column; the key is used in presets, defaults, saved choices, columns=
Builtin=trueone of the 15 columns the list renders itself; only Name, Group, Order, Description, Copy, Align, Policy[] can be changed (their defaults live in expSubitemsBuiltinColumn::definitions())
Class=a subclass of expSubitemsColumn, constructed with (key, settings)
Handler=class::methoda static method (node, settings, column) returning the value
Template=design:...tpla template; $node, $column, $key; output = cell, text = value
Field=for the shipped family classes: which column of the family
Name=the column's name, translated in the context design/admin/node/view/full
Group=Basic, Node, Object, Version, Location, URLs, SEO, Dates, People, Relations, Translations, Workflow, Users, Media, Technical, Custom; translated like Name=
Type=text, html (trusted markup), number, date, datetime, bool, link (http(s), // or / only), code, list, image
SortField=path, path_string, published, modified, section, depth, class_identifier, class_name, priority, name, modified_subnode, node_id, contentobject_id, visibility, or attribute:<class>/<attribute>; empty: not sortable
Policy[]module/function entries the user must all have
Description=the tooltip in Table options, translated like Name=
Copy=truea click on a cell copies the value
Align=rightright aligned
Order=position in Table options and among defaults
SiteAccess=url and SEO columns: the public siteaccess (empty: DefaultAccess)
Scheme=public_url: https (default) or http when SiteURL has none
TitleFormat=page_title, title_length: name or path
Limit=related name lists: the most names (default 10, at most 100)
Attributes[]main text, image and file fields, and the teaser template: identifiers tried first
Length=the teaser template: characters
WordsPerMinute=readingtime: words a minute (default 200)

settings/subitems.ini

SettingMeaning
[SubitemsSettings] DefaultColumns[]the visible columns where no [Defaults_*] matches (name;published;translations;priority)
AttributeColumns=enabled/disabled: the automatic attribute columns
AttributeColumnsExcludedDataTypes[]datatypes never offered as attribute columns (ezuser)
AttributeColumnsDataTypePolicy[<datatype>]policies an attribute column of that datatype needs (; separated)
CSVExport=enabled/disabled: Export CSV and the view content/subitemsexport
CSVLimit=the most rows one export writes (5000)
PageSizes[]the page sizes offered (10, 25, 50, 100)
[Preset_<id>] Name=, Columns[]a preset everybody can choose
[Defaults_<id>] Subtree[], ParentClassIdentifiers[], Columns[]defaults for a place

The server API

Three ezjscore functions, [ezjscServer_expsubitems] in extension/ezjscore/settings/ezjscore.ini (class expSubitemsServerFunctions), and one content view. Every call needs a logged-in user with access to the admin and read access to the parent; keys are checked against the registry, and nothing from the request is ever used as a class, function or template name. ezjscore wraps every answer as { "error_text": "", "content": ... }.

  • ezjscore/call/expsubitems::columns::<parent>: the columns the user may see (key, name, group, type, sortable, align, description, copy, builtin, order), defaults, presets (source: ini or user), the saved preference (visible, preset, page_size, saved), page_sizes, csv_export. On the reference installation, as the admin, the media root offers 138 columns (129 from the INI, 9 attribute columns):

    {"key":"pagetitle","name":"Page title in the browser","group":"SEO","type":"text","sortable":false,"align":"",
     "description":"The public site's title for the item's page, worked out as its pagelayout does, without rendering the page.",
     "copy":true,"builtin":false,"order":700}
  • ezjscore/call/expsubitems::rows::<parent>::<limit>::<offset>::<sort key>::<order 0|1>[::<name filter>] with columns=a,b,c (POST or GET): the ezjscnode::subtree answer, every item with columns: { <key>: { v: <value>, h: "<html>" } } for the requested non-built-in keys. The sort key is a column key whose column sorts, or one of the old names (published_date, modified_date, node_id ...); anything else sorts as the parent does. Two children of the media root on the reference installation, with columns=parentnodeid,urlalias,pagetitle,childrencount,version,readingtime:

    {"parentnodeid":{"v":43,"h":"43"},"urlalias":{"v":"media/banners","h":"<code>media/banners</code>"},
     "pagetitle":{"v":"Banners - Fit & Healthy","h":"Banners - Fit &amp; Healthy"},"childrencount":{"v":4,"h":"4"},
     "version":{"v":1,"h":"1"},"readingtime":{"v":null,"h":""}}
    {"parentnodeid":{"v":43,"h":"43"},"urlalias":{"v":"media/clients-partners","h":"<code>media/clients-partners</code>"},
     "pagetitle":{"v":"Clients & Partners - Fit & Healthy","h":"Clients &amp; Partners - Fit &amp; Healthy"},
     "childrencount":{"v":12,"h":"12"},"version":{"v":1,"h":"1"},"readingtime":{"v":null,"h":""}}
  • ezjscore/call/expsubitems::savepreference[::<parent>], POST preference=<json> (with the form token): { "visible": [...], "preset": "seo"|null, "page_size": 25, "presets": { "<id>": { "name", "columns" } } }, every key optional; stored for the parent's navigation part.

  • content/subitemsexport/<parent>/(columns)/a,b,c/(sort)/<key>/(order)/0|1: the CSV (below).

PHP code can use the same pieces: expSubitemsColumnRegistry::instance() (availableColumns( $parent ), column( $key, $parent ), resolveColumns( $keys, $parent ), defaults(), presets(), sortFor()), and expSubitemsServerFunctions::columnValues( $nodes, $columns ) for the cells (it prefetches; prefetch() and cell( $column, $node ) are the two steps on their own).

Performance

Only the visible columns are computed, and only for the rows of the page (the page size), never for the whole subtree. The 15 built-ins cost nothing extra: they come with the node, as before. Most other columns read the loaded node or object and cost no query.

The others load what they read once for the page, not once per row: before computing any cell, the rows function and the CSV export call prefetch( $nodes ) on every requested column with the page's nodes, and the column loads its data for all of them in one query, into the same per-request memo its value() reads. A prefetch only changes the number of queries, never a value (the tests compute every column both ways and compare), and one that fails just leaves the column to load per row. Loaded once per page:

DataColumns
The data map (attributes of the current version and language)word count, text length, reading time, attribute count, every image and file column, page title and the meta columns, tags, the automatic attribute columns
Version rowsversion count, drafts, draft authors, latest draft, archived, pending, rejected, initial creator, contributors, version created
Readable children, per parent (the user's content/read limitations applied, as childrenCount() does)children count
Children per classchild classes
URL alias rowsalias count, all URL aliases, custom aliases, custom alias count, history count
Locations of the objectlocation count, other locations
Relation counts (all types, both ends published)related count, reverse related count
Countsworkflow processes, search index words, view count

Columns of one row that read the same data share it, and lookups that are the same for every row (the parent's name, a class's groups, a section, the public siteaccess's settings, a user's name) are done once per request. The rows function and the CSV export empty the memo first, so a persistent worker never answers from an earlier request. On MongoDB the grouped queries are skipped and the columns load per row. Still per row: Subtree size (a count over each whole subtree), Newest child, the URL alias based columns for the odd node whose alias the kernel leaves empty, the user columns, and Teaser (it renders an XML text block); keep the heavy ones for small pages.

A family class (expSubitemsFieldColumn) lists in prefetchSets() which Field= values read which set, and has a prefetch<Set>( $nodes ) for each; a column class of your own overrides prefetch().

Measured on the reference installation (SQLite, as the admin, on the command line; median of 5 runs, each in a fresh process): every one of the 114 non-built-in columns at once, for the first 10 children of the media root and for the first 50 and 100 nodes of the content tree.

RowsQueriesTimeTime without Teaser and Subtree size
10130 (229 before page prefetch)186 ms (264 ms)107 ms (135 ms)
50814 (1353)1.6 s (1.9 s)558 ms (714 ms)
1001671 (2759)3.2 s (3.4 s)1.27 s (1.32 s)

CSV export

Export CSV in Table options, or content/subitemsexport/<parent node id>/(columns)/a,b,c/(sort)/<key>/(order)/0|1 (view parameters; a ?columns= query string is not read): every child the user may read (up to CSVLimit, fetched 100 at a time), the given columns (without columns=: the user's saved choice, else the defaults), in order; the header row holds the column names. UTF-8 with BOM, comma separated, CRLF; cells starting with =, +, - or @ get a leading ' so a spreadsheet does not run them. Built-ins are included (except the thumbnail), lists are joined with , , dates written as Y-m-d H:i:s, bools as 1/0, sizes in bytes. The file is named after the parent. CSVExport=disabled removes the button and the view.

Where the choice is stored

The user's choice is one eZPreferences value, admin_subitems_table, a compact JSON document:

{"v":1,"parts":{"ezcontentnavigationpart":{"visible":["name","urlalias","pagetitle"],"preset":null}},
 "page_size":25,"presets":{"mine":{"name":"Mine","columns":["name","nodeid"]}}}

The visible columns and the chosen preset are kept per navigation part (* when saved without a parent), the page size and the own presets once. It is kept under 4000 bytes on every database (the Oracle limit); a choice that does not fit is refused, not cut. The old rows-per-page preference (admin_list_limit) is still used while no page size was saved.

Where the code lives

WhatWhere
The column base class, the shared formatting, the memo and the data map prefetchkernel/classes/subitems/expsubitemscolumn.php (expSubitemsColumn)
Registry, built-ins, Handler/Template/attribute wrappers, preference, server functions, CSVkernel/classes/subitems/*.php
The shipped column classeskernel/classes/subitems/columns/*.php (expSubitemsFieldColumn is the family base: Field=, prefetchSets(), the grouped count helper)
The column cataloguesettings/subitemscolumns.ini
Defaults, presets, CSV, attribute columnssettings/subitems.ini
The template columnsdesign/standard/templates/subitems/columns/*.tpl
The table and Table optionsdesign/<admin design>/javascript/ezajaxsubitems_expdatatable.js, design/<admin design>/templates/children_detailed.tpl, extension/expui/design/standard/javascript/exp/datatable.js
The CSV viewkernel/content/subitemsexport.php

Tests

php vendor/bin/phpunit tests/tests/kernel/classes/subitems/            # everything (100 tests)
php vendor/bin/phpunit tests/tests/kernel/classes/subitems/columns/    # the catalogue and the prefetch (64 tests)

The catalogue tests start the kernel on the admin siteaccess with the installation's own database and check every column against real nodes: the content root, the media root, the users root, the admin user, and nodes found by what they hold (an image, a file, tags, an XML text, relations, a rating). They check that every block builds, names a known group, type and field, that its sort field is accepted, that every column gives a JSON-safe value and one-line CSV text for four very different nodes, that columns that do not apply give null, that policies decide availability, that no node ever shows an empty URL alias, and the three worked examples above. expSubitemsPrefetchTest computes every column (and the attribute columns) for pages below the content, media and users roots once row by row and once with the page prefetch, as the admin and as anonymous, and requires the same cells; and that after the prefetch the rows of the prefetched columns need no query. A test that needs data the database does not have is skipped, not failed.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x