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

LoveStack features in Exponential 6

LoveStack is Mugo Web's distribution of the legacy kernel originally published by eZ Systems (mugoweb/ezpublish-legacy on GitHub and Packagist). Over the years Mugo Web added a number of valuable features and fixes to…

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/bc/6.0/lovestack.md

On this page

LoveStack features in Exponential 6

LoveStack is Mugo Web's distribution of the legacy kernel originally published by eZ Systems (mugoweb/ezpublish-legacy on GitHub and Packagist). Over the years Mugo Web added a number of valuable features and fixes to it. Exponential 6.0.15 brings 36 of them into the Exponential distribution, each one rebuilt in Exponential's own APIs, documented and covered by tests, so that every Exponential site can use them together with Exponential's own features. With thanks to Mugo Web, whose work this is built on.

This page is the overview: what each feature does, who it is for, how to switch it on, its settings and defaults, what changes on an upgrade and on a new installation, the test that covers it and the LoveStack commit it comes from. The detailed pages are listed in More documents.

In one sentence: nothing changes on an existing site unless you switch it on, except plain bug fixes, a few new warnings and log settings, and the security checks for logging out (L03) and for uploaded images (L05, L06).

If you run Exponential and never ran LoveStack, there is nothing to do: the features are in 6.0.15, and the ones that could change how a site behaves are off until you turn them on. If you run LoveStack, see Moving a site from LoveStack.


Source reference (where the features come from, and when)

The LoveStack features brought into Exponential were taken from Mugo Web's repository mugoweb/ezpublish-legacy as it stood on the day of the port, 12 October 2026. Every feature, test and comparison in this document refers to that exact commit, so the work can be reproduced and checked against the same source at any time.

Repositoryhttps://github.com/mugoweb/ezpublish-legacy (default branch master, not archived)
Commit used for the porte61e9fdf0ca464197b79935ef784ed459721aa87, "Merge pull request #238 from mugoweb/php8-fix"
Source tree at that commithttps://github.com/mugoweb/ezpublish-legacy/tree/e61e9fdf0ca464197b79935ef784ed459721aa87
Date of that commit23 February 2026, 08:49:45 UTC (still the latest commit on master when checked on 12 October 2026)
Latest release thenv2025.03.1-1, 1 March 2025
Common ancestor with Exponential3429aa91bba018f518fcb41757c9d627a0a73c0f, 9 March 2016 (upstream ezsystems/ezpublish-legacy)
Mugo Web's work compared3429aa91bb..e61e9fdf0c: compare view
Time since the last change, at the time of the port231 days (7 months and 19 days) since the last commit; 590 days (over 19 months) since the last release

To reproduce: git clone https://github.com/mugoweb/ezpublish-legacy && git -C ezpublish-legacy checkout e61e9fdf0ca464197b79935ef784ed459721aa87. The commit ids named for each feature (L01–L36) below are commits in that repository and open as https://github.com/mugoweb/ezpublish-legacy/commit/<id>.


The features in plain terms

What the 36 features are, grouped by what they do to an existing site after the upgrade.

On for every site: fixes and safety checks

FeatureWhat you'd see
L03Logging out really ends the sessionafter logout the session and its cookie are gone, not just given a new id
L05Uploaded images are checked by their contenta file that is not a listed image type (a renamed file, HEIC, SVG) is refused
L06Package thumbnails are checked the same waya fake image as a package thumbnail or style image is refused
L11Database errors carry the driver's error numberdevelopers can tell "duplicate key" from "table missing" in code
L12A warning when a change clears every view cacheone log line saying a big change cleared all view caches
L20The Locations window in the edit form no longer forces "Visible"a hidden location stays hidden when you add another
L21No stray line breaks in selection and matrix fieldscleaner output
L24The sub/superscript dialog closes when you press OKwas already the case in Exponential
L31Templates can tell layout views apart againbug fix for designers
L34Very large numbers no longer stop the search indexbug fix
L35Relations of related objects stay out of the search indexwas already the case in Exponential
L36Hiding content by cronjob also updates the search indexhidden content stops showing up in search
PHP 8PHP 8 fixes from LoveStack, reproduced and fixed where still neededfewer deprecations and errors on PHP 8.1 to 8.5

On for every site: small visible changes

FeatureWhat you'd see
L07PHP deprecations get their own debug level and logvar/log/deprecated.log; the debug bar counts them instead of listing them
L08Log file size is a setting, 2 MB by defaultfewer, longer log files (was 200 KB)
L09A warning when a template operator parameter has no defaultfor template developers
L15A Copy button on the admin full viewuntil now Copy was only in the right-click menu
L27Template operators rawurlencode and rawurldecodefor template developers
SameSiteLoveStack's [Session] SameSite setting is read toosettings written for LoveStack keep working

New options, off until you switch them on

FeatureWhat you'd see
L10An "edit" link format for the debug output's list of used templatesfor template developers
L13Audit records for adding a location and changing the main locationnew entries in the audit console (removing a location is recorded already)
L14Site data readable in templates, plus an admin listfor developers and administrators
L16"Alternative text is required" for an image field, per classeditors can't save an image without alt text where it's on
L17"Trim the stored value" for text line fields, per classleading and trailing spaces removed on save
L18Your own PHP class can make an object's name or URL aliasfor developers
L19Class filters can default to "include"changes fetch results, so off by default
L22Hidden custom tagscustom tags that exist but are not offered in the editor's list
L29Extra headers per error page (for example Cache-Control on 404)set in error.ini
L30ezjscore search result order from the search settingsships with the order it always had
L32Request addresses decoded once (%2B stays +)some view parameters change, so off
L33The double quote is cleaned from IRI URL aliasesnew aliases can differ from older ones, so off

On for new installations, off for upgrades

FeatureWhy it needs careHow it is handled
L01ezjscnode (node data as JSON/XML) can require a policyfront-end JavaScript reading it for anonymous visitors would stop working; today anyone who may read a node can read its metadata this waynew installations on, upgrades off; the list of callers says who uses it
L02Registration needs a policysites relying on open registration would lose the "register" linknew installations only
L04Logins become unique in the databaseadding the index fails if duplicate logins exist; LDAP or SSO may create duplicatesnew installations have the index; upgrades get a duplicate report first and the index only on request
L23Custom tag controls in the rich text editorthe editor looks differentnew installations on, upgrades off

New APIs for developers (additions only, nothing existing changes)

Feature
L18{MyClass} in a class's name pattern: your own PHP class computes the name or URL alias
L25eZURI::build( $url, $full ): build a site URL in one call
L26eZMailTransport::send( $mail, $transport ): choose the mail transport per message
L28[Include path/*.ini] inside settings files, to split large settings
L31eZTemplateDesignResource::setKeyValue()

In short

The visible new features are required alt text, trimmed text fields, a Copy button, location audit records, custom tag controls in the editor, extra error-page headers and settings-file includes. The security changes are ezjscnode behind a policy, registration that can be closed, a real logout, unique logins and image uploads checked by their content. Everything else is small bug fixes and developer helpers.


Feature by feature

Each entry says who it is for (editor, administrator, developer), what it does, its settings with their shipped defaults, what a new installation and an upgraded site get, how to switch it on, the test that covers it and the LoveStack commit it comes from. Settings you change go into an override (settings/override/<file>.append.php) or a siteaccess, never into the shipped file; clear the INI cache afterwards (php bin/php/ezcache.php --clear-tag=ini). Test files are under tests/tests/ and run on their own: php vendor/bin/phpunit tests/tests/<path>.

Security and sessions

L01 — Node data calls can require a policy

For administrators. The ezjscore calls ezjscnode::load, ::subtree and ::updatepriority return a node's name, ids, remote id, owner, section, dates, class and translations as JSON or XML to every user who may read the node, anonymous visitors included. With RequirePolicy=enabled a user also needs the policy ezjscore / call with the function list ezjscnode.

Settingsextension/ezjscore/settings/ezjscore.ini [ezjscServer_ezjscnode] Functions[]=ezjscnode, RequirePolicy=disabled. RequirePolicy works for every [ezjscServer_<name>] block: not set = Functions[] checked as before (a refused call answers with its error text); disabled = not checked; enabled = checked, and a request whose calls are all refused for that reason is answered with 403 Forbidden
New installationRequirePolicy=enabled (written to settings/override/ezjscore.ini.append.php); the Editor role gets ezjscore / call with ezjscnode, which the sub-items list and the image size preview of the rich text editor use. Administrators have it through full access
Upgradeunchanged (RequirePolicy=disabled)
Switch ongive ezjscore / call with the function list ezjscnode to every role whose users use the administration without full access, then set RequirePolicy=enabled in settings/override/ezjscore.ini.append.php. The shipped designs never call ezjscnode for anonymous visitors; see who calls ezjscnode
Testextension/ezjscore/ezjscServerRouterPolicyTest.php
LoveStackaa307a7ff3 (2024)
GuideRoles and policies, section 8

L02 — Registration can require a policy

For administrators. Registering a new account (user/register) can be taken out of the list of views everyone may open, so it needs the policy User / Register. The login pages of admin and admin4, the standard design and its login toolbar, the media and the starter designs show the register link or the Sign Up button only to a user who may open user/register, so a site without open registration shows no dead link.

Settingssite.ini [RoleSettings] PolicyOmitListExclude[] (new, empty) takes single entries out of PolicyOmitList[] after every settings file is read, so the entries extensions add stay. user/register stays in the shipped PolicyOmitList[]
New installationPolicyOmitListExclude[]=user/register: registration needs the policy. For open registration, give the Anonymous role User / Register
Upgradeunchanged: registration and its link stay open
Switch onadd PolicyOmitListExclude[]=user/register under [RoleSettings] in settings/override/site.ini.append.php; give the Anonymous role User / Register where registration should stay open
For developersexpPolicyOmitList::entries(), ::excluded(), ::omits( $module, $view ); in templates fetch( 'user', 'can_open', hash( 'uri', 'user/register' ) )
Testskernel/classes/expPolicyOmitListTest.php, kernel/content/eZLoginTemplatesRegisterLinkTest.php
LoveStack98854ab935 (2021)
GuideRoles and policies, section 8

For everyone. Logging out removes the session and its contents instead of giving it a new id with its contents kept. Every session handler sends the session cookie expired with the same path, domain, Secure, HttpOnly and SameSite it was set with, so the browser drops exactly that cookie, and the old session id no longer signs anyone in. A session started later in the same request gets a new id, under PHP-FPM and Velocity alike.

Settingsnone
New installation and upgradeon
Note for developerscode of your own that reads session variables after eZUser::logoutCurrent() finds the session empty. New: eZSession::expiredCookie(), eZSession::expireCookie()
Testkernel/classes/eZUserLogoutTest.php
LoveStack13ace6c9c8 (2019)
GuideSecurity and audit, section 1

L04 — One account per login

For administrators. A login belongs to one account. A console command lists the logins more than one account has (also those that differ only in case) and adds a unique index on ezuser.login once there are none. A first version of a user account whose form did not validate is not stored, and a draft, a package import, the content API's account string and a first LDAP sign-in no longer give an account a login another account has; two requests creating the same account at once end with one account.

Commands./console exp:user-login-check (report only; --show-logins, --json) and ./console exp:user-login-check --fix-index (adds the index after a clean report, refuses otherwise). Exit code 0 clean or index added, 1 duplicates found or index refused, 2 error
New installationthe kernel schema of every engine has the unique index
Upgradethe database update does not add the index, because it would fail on duplicates. Run the report, resolve what it lists, then --fix-index
For developersexpUserLoginIntegrity::duplicates(), indexStatus(), addUniqueIndex(), loginTakenBy(), storeUser()
Testkernel/classes/expUserLoginIntegrityTest.php
LoveStack826e1d4647 (2020)
GuideSecurity and audit, section 7

L05 — Uploaded images are checked by their content

For everyone. PHP's fileinfo reads the type of an uploaded image from its content, and the type must be on an allow-list. A refused file is not stored. This applies to the image datatype in the edit form, content/upload, the rich text editor's upload dialog, the AJAX uploader, WebDAV and imports; eZContentUpload refuses such a file before it creates an object.

Settingsimage.ini [ImageUploadSettings] ValidateMIMEType=enabled, AllowedMIMETypes[] = image/jpeg, image/png, image/gif, image/webp, image/avif, image/tiff, image/bmp. SVG is not on the list
New installation and upgradeon: a file that is not a listed image by content (a renamed file, HEIC, SVG) is refused with "A valid image file is required." or "Images of the type %1 are not accepted."
To accept another typeadd it to AllowedMIMETypes[] in an override. ValidateMIMEType=disabled keeps only the getimagesize() check. Without the fileinfo extension that check decides, and one warning per process says so
For developersexpImageUploadValidator::validate( $path, $originalName = null ) returns array( 'valid' => bool, 'mime' => string )
Testskernel/classes/expImageUploadValidatorTest.php, extension/ezjscore/ezjscServerFunctionsAjaxUploaderImageTest.php
LoveStackc8e45fced7 (2017)
GuideBehaviour changes of October 2026

L06 — Package thumbnails are checked the same way

For administrators. The package wizard checks the thumbnail of a new package and the images of a style package with the same content check and allow-list as L05.

Settingsthose of L05
New installation and upgradeon
Testkernel/classes/packages/eZStylePackageCreatorTest.php
LoveStack04b3b6985a (2018)
GuideBehaviour changes of October 2026

LoveStack's session SameSite setting is read too

For administrators of sites coming from LoveStack. site.ini [Session] SameSite=, the name LoveStack uses for the SameSite attribute of the session cookie, is read when Exponential's CookieSameSite is not set (CookieSameSite wins when both are), and noted once per request at the deprecated level of the debug output. Nothing changes for visitors; rename the setting to CookieSameSite to silence the note.

Testlib/ezsession/eZSessionSameSiteAliasTest.php
LoveStacke56cb305f0 (2025)
GuideSecurity and audit, section 1

Diagnostics and logging

L07 — PHP deprecations get their own log

For administrators and developers. PHP deprecations have a debug level of their own. They are written to var/log/deprecated.log, each distinct message once per request, and only counted: the debug bar shows their number (depr), they stay in the page's warning count, and none is kept in memory or listed with the other messages. On PHP 8 this keeps the debug output readable and its memory use low.

Settingssite.ini [DebugSettings] DeprecatedLog=enabled. Add AlwaysLog[]=deprecated to write them while debug output is off as well
New installation and upgradeon; DeprecatedLog=disabled keeps them warnings as before
For developerseZDebug::LEVEL_DEPRECATED, eZDebug::SHOW_DEPRECATED (part of SHOW_ALL), eZDebug::writeDeprecated(), eZDebug::deprecatedCount()
Testlib/ezutils/eZDebugDeprecatedTest.php
LoveStackfbbd333a85, e20570a7ad, b7832d110e (2025)
GuidePHP deprecations and log file sizes

L08 — Log file size in site.ini

For administrators. The size at which log files are rotated, and how many old files are kept, are settings, read by eZLog and eZDebug.

Settingssite.ini [FileSettings] LogFileMaxSize=2097152 (2 MB), LogFileRotateCount=3. eZLog::setMaxLogSize(), setLogrotateFiles() and the constants in config.php still win over them
New installation and upgradelog files are rotated at 2 MB instead of 200 KB; LogFileMaxSize=204800 keeps the old size
Testlib/ezfile/eZLogMaxSizeTest.php
LoveStacke39dde30ff (2021)
GuidePHP deprecations and log file sizes

L09 — A warning for an operator parameter without a default

For template developers. A template operator parameter that the template leaves out and the operator gives no default value for is null, with the warning Operator '<op>' has no default value for parameter '<name>', once per operator and parameter in a request (a compiled template is warned once, when it is compiled).

New installation and upgradeon; only the warning is new
Testlib/eztemplate/eZTemplateOperatorDefaultWarningTest.php
LoveStack0bb0bac618 (2016)
GuideAn operator parameter without a default value

For template developers. The "Edit" links in the debug output's list of used templates can point to an address of your choice, for example the template editor of the administration.

Settingssite.ini [DebugSettings] UsedTemplateEditUrl=, a sprintf() format: %1$s the editor address with the file, %2$s the siteaccess, %3$s the template file. Empty (shipped) = the link the list always had
New installation and upgradeunchanged until set
Testkernel/common/eZTemplatesStatisticsReporterEditUrlTest.php
LoveStackfb20bee0d2 (2019)
GuideEdit links in the list of used templates

L11 — Database errors carry the driver's error number

For developers. eZDBException::getCode() is the driver's error number of the failed statement on every driver, as errorNumber(): MySQL's number, PostgreSQL's SQLSTATE (a string), SQLite's result code, Oracle's ORA number; MongoDB keeps the server's code in errorNumber(). The "database unavailable" page (HTTP 503) also recognises the error numbers that say the connection went away or could not be made.

New installation and upgradeon. PostgreSQL's errorNumber() is the SQLSTATE instead of 1; with the exception handling on, MySQL on PHP 8.1 and later throws eZDBException instead of mysqli_sql_exception
Testlib/ezdb/eZDBExceptionCodeTest.php
LoveStack3d18f47551 (2017)
GuideKnow your database driver

L12 — A warning when a change clears every view cache

For administrators. When a change would clear the view caches of site.ini [ContentSettings] CacheThreshold nodes or more and all view caches are expired instead, a warning in the log names the number of nodes and the threshold (it was a debug message).

New installation and upgradeon
Testkernel/classes/eZContentCacheManagerThresholdWarningTest.php
LoveStackf9691221a3 (2018)
GuideCaches, usual questions

Content, datatypes and the administration

L13 — Audit records for location changes

For administrators. Location changes are events of Exponential's audit trail (channel content): content.node.add once per added location, content.node.remove with whether the removed location was the main one, and content.node.main when an editor chooses another main location or the next location takes the place of a removed main one. The audit console shows them as Location add, Location remove and Main location change. LoveStack's names location-assign, location-remove and main-node-update are mapped to these events, so eZAudit::writeAudit() calls and audit files of those names keep working.

Settingsaudit.ini [AuditEventSettings] Enabled[]; [AuditCompatSettings] Map[] and [AuditSettings] AuditFileNames[] hold the LoveStack names
New installation and upgradecontent.node.remove on, as before; content.node.add and content.node.main off
Switch onEnabled[]=content.node.add and Enabled[]=content.node.main under [AuditEventSettings] in settings/override/audit.ini.append.php
Testkernel/content/eZAuditLocationTest.php (needs a database; rolls back what it writes)
LoveStack9c931192e0 (2017)
GuideAudit reference: location changes

L14 — Site data in templates and in the administration

For developers and administrators. A template can read one row of ezsite_data by name, for names you list; Setup > Site data (setup/sitedata, policy setup/system_info) lists the rows with a filter and paging, in admin, admin3 and admin4.

Settingssite.ini [SiteDataSettings] TemplateReadable[] (empty: nothing is readable from templates)
Template{def $row = fetch( 'content', 'site_data', hash( 'name', 'my-flag' ) )} gives the eZSiteData object, or false when the name is not listed or not stored
New installation and upgradenothing readable until a name is listed; the admin list is there
For developerseZSiteData::createNew(), templateReadableNames(), isTemplateReadable(), fetchList(), fetchListCount()
Testskernel/content/eZContentFunctionCollectionSiteDataTest.php, kernel/classes/eZSiteDataCreateTest.php
LoveStack55029bd473, a679a13176, 94b7b6c239 (2017–2019)
GuidesSite data in templates, Site data in System information

L15 — A Copy button on the admin full view

For editors. The full view of the administration (admin, admin3, admin4) has a Copy button next to Move, active with create access at the item's parent as in the context menu. It opens the same copy steps as the context menu.

New installation and upgradeon
Testkernel/content/eZAdminFullViewCopyButtonTest.php
LoveStack4d56593614 (2019)
GuideCopy from the full view

L16 — Required alternative text for image fields

For editors and administrators (accessibility). An image attribute can require an alternative text. The edit form, the online editor's upload dialog (also used by Tiptap) and the AJAX uploader of relation fields then refuse an image without one; the AJAX uploader has an alternative text field for classes with an image attribute. Packages carry the option.

Settingsthe class attribute option Alternative text is required on the class edit page (eZImageType::ALT_TEXT_REQUIRED_FIELD, data_int2)
New installation and upgradeoff for every class
Switch onper image attribute, on the class edit page
Testskernel/classes/datatypes/eZImageTypeAltTextTest.php, extension/ezjscore/ezjscServerFunctionsAjaxUploaderAltTextTest.php
LoveStacka28863d9c0 (2017)
GuideAlternative text is required

L17 — Trim the stored value for text line fields

For editors and administrators. A text line attribute can remove spaces at the start and the end of its value, in the edit form, information collection, imports and uploads.

Settingsthe class attribute option Trim the stored value (eZStringType::TRIM_FIELD, data_int2)
New installation and upgradeoff for every class
Switch onper text line attribute, on the class edit page
Testkernel/classes/datatypes/eZStringTypeTrimTest.php
LoveStack6a5c7dd23e (2020)
GuideTrim the stored value

L18 — Names made by a PHP class

For developers. A class's object name pattern or URL alias pattern that starts with {MyResolver} is resolved by your PHP class MyResolver, when it is listed and implements expNamePatternResolverInterface. Any other name is logged and the pattern is resolved from its tokens as usual.

Settingscontent.ini [NamePatternSettings] ResolverClasses[] (empty)
New installation and upgradenothing changes until a class is listed
For developersexpNamePatternResolverInterface::resolveNamePattern( $object, $version, $translation, $length, $sequence ); eZNamePatternResolver::resolve(), customResolver(), limitName(). The constructor and resolveNamePattern() are unchanged
Testskernel/classes/eZNamePatternResolverClassTest.php, kernel/classes/eZNamePatternResolverLimitTest.php
LoveStack95d86f5990 (2020)
GuideNames made by a PHP class

L19 — Class filter default for fetches

For template developers. The class filter type the fetch functions list, tree, list_count, tree_count and calendar use when a fetch gives class_filter_array without class_filter_type.

Settingscontent.ini [FetchSettings] DefaultClassFilterType= (empty: today's results, the array is ignored; include: filter by the array)
New installation and upgradeempty
Testkernel/content/eZContentFunctionCollectionClassFilterTypeTest.php
LoveStack9c0ff40a78 (2018)
GuideClass filter default for fetches

L20 — The Locations window keeps a hidden location hidden

For editors. In the edit form's Locations window an existing location starts at "Unchanged", not "Visible", so publishing no longer reveals a hidden location; a new location starts as it was given (EZP-26501).

New installation and upgradeon (a fix)
Testkernel/content/eZEditLocationsVisibilityTest.php
LoveStackf1b7f056b4 (2016)
GuideThe Locations window

L21 — Selection and matrix fields without stray line breaks

For designers and visitors. The view templates of the selection and matrix datatypes write no stray <br />; several selected options are separated by one <br /> each.

New installation and upgradeon, for every site that does not override these templates
Testkernel/datatypes/eZSelectionMatrixViewTemplateTest.php
LoveStackeee7f69fc3, 67eec8f972, 492a946963
GuideSelection and matrix fields

Rich text editor

L22 — Hidden custom tags

For administrators and editors. Custom tags you list are not offered for new tags in the editors (TinyMCE 3, TinyMCE 8, Tiptap). Where a hidden tag is already in a text it is still shown, rendered, editable and saved back unchanged.

Settingscontent.ini [CustomTagSettings] IsHidden[] (none hidden)
New installation and upgradenone hidden
For developerseZOEXMLInput::hiddenCustomTags(), offeredCustomTags(), the keys hidden and preview of getCustomTagDefinitions()
Testextension/ezoe/expOECustomTagListTest.php
LoveStacke21ef46691 (2019)
GuideHidden custom tags

L23 — Custom tag controls in the rich text editor

For editors. A focused custom tag gets a bar to move it up or down, edit it and remove it (its content stays), also with Alt+Shift+Up, Alt+Shift+Down, Alt+Shift+E and Alt+Shift+Delete; Backspace in an empty block custom tag removes it; every block custom tag shows its name as a label; a tag's dialog shows images/editor/custom_tags_thumbs/<name>.png from a design as an example. TinyMCE 3 gets the plugin exp_customtag_controls (built on TinyMCE 3's plugin API and ezjscore's jQuery, no YUI), TinyMCE 8 the buttons in its custom tag toolbar, Tiptap the same in exp_oe_tiptap 0.1.2.

Settingsezoe.ini [EditorSettings] CustomTagControls=disabled; stylesheet ezoe_customtags.css (acts only when on)
New installationCustomTagControls=enabled
Upgradeunchanged (disabled)
Switch onCustomTagControls=enabled in settings/override/ezoe.ini.append.php, then clear the INI cache and the packed scripts: php bin/php/ezcache.php --clear-tag=ini --clear-id=ezjscore-packer
Testextension/ezoe/expOECustomTagAssetsTest.php
LoveStack63334f1681 (2019; its custom_tags_controls plugin carries "Copyright 2014, Mugo Web")
GuideCustom tag controls

L24 — The sub/sup dialog closes on OK

For editors. The sub and sup custom tag dialog of TinyMCE 3 closes when you press OK. Exponential's tag_custom.tpl already had this fix, so nothing changed; it was checked in the browser on TinyMCE 3 and Tiptap (TinyMCE 8 has its own sub and sup buttons).

Testbrowser check only (a JavaScript dialog)
LoveStack3a8c14bc0c (2019)

Developer APIs and settings

L25 — eZURI::build() builds a site URL in one call

For developers. eZURI::build( string $url, bool $full = false, bool $htmlEscape = true ) gives the same link as the ezurl template operator (index file and siteaccess in front; with $full scheme and host). Use $htmlEscape = false for a URL in a header or a JSON answer.

Testlib/ezutils/eZURIBuildTest.php
LoveStackf2284944b2 (2020)
GuideURLs, for developers

L26 — One message with another mail transport

For developers. eZMailTransport::send( eZMail $mail, ?string $transportType = null ) sends one message with another transport of site.ini [MailSettings] TransportAlias[] (for example file) without changing the setting; the mail gate applies as before.

Testlib/ezutils/eZMailTransportSendTest.php
LoveStackdf07cb1ef5 (2019)
GuideTesting without sending mail

L27 — rawurlencode and rawurldecode template operators

For template developers. RFC 3986 encoding (%20 for a space) in templates: {$value|rawurlencode}. urlencode and urldecode are unchanged. All four operators give an empty text for a value that is not set.

Settingstemplate.ini [PHP] PHPOperatorList[rawurlencode], PHPOperatorList[rawurldecode] (shipped)
New installation and upgradeavailable
Testkernel/common/eZTemplateRawURLEncodeOperatorTest.php
LoveStack627004e5c4 (2021)
GuideEncoding a value for a URL

L28 — [Include …] inside settings files

For administrators and developers. A line [Include site.d/*.ini] in a settings file reads other files at that place: the pattern is relative to the including file, wildcards are allowed, the files are read in name order, includes nest, a loop is read once with a warning and a pattern without a match is a notice. The included files are part of the INI cache, so php bin/php/ezcache.php --clear-tag=ini and exp:velocity deploy pick up their changes. The settings page, the classic settings editor and exp:ini keep the line as written and do not expand it.

New installation and upgradeonly active where a file has such a line
For developerseZINI::includedFiles()
Testlib/ezutils/eZINIIncludeTest.php
LoveStackf7c382bc2b (2018)
GuideSplitting a large settings file

L29 — Response headers for error pages

For administrators. Each HTTP error page can send extra response headers, after its status lines; they are stored with the page in the view cache and sent again from it. An invalid header name or a value with a line break is left out with a warning.

Settingserror.ini [HTTPError-<code>] HeaderList[<name>]=<value>, for example HeaderList[Cache-Control]=no-store under [HTTPError-404] (empty by default)
New installation and upgradenothing changes until an entry is added
Testkernel/error/ErrorHeaderListTest.php
LoveStack97690e9c93 (2017)
GuideResponse headers of error pages

L30 — The order of search results in the editors' dialogs

For administrators. The ezjscore search (used by the editor's embed and link dialogs and the relation search) sorts eZ Find results by the search settings instead of always newest first.

Settingsezfind.ini [SearchSettings] SortBy[]; ezjscore ships SortBy[published]=desc, the order it always used
New installation and upgradeunchanged order; without eZ Find or the setting the order stays newest first
Testextension/ezjscore/ezjscServerFunctionsJsSearchSortByTest.php
LoveStack3d2d337b0d, 3af1ec3aee (2025)
GuideThe order of search results

L31 — Templates can tell layout views apart

For designers and developers. Every node view sets the override key layout (empty outside layout/set, the layout of layout/set kept), so a template override can match on it again. New: eZTemplateDesignResource::setKeyValue( string $key, $value, bool $override = true ).

New installation and upgradeon
Testkernel/common/eZTemplateDesignResourceSetKeyValueTest.php
LoveStack856a95e240 (2016)
GuideThe layout key

L32 — Request addresses decoded once

For administrators. The address of a request is decoded once instead of twice, so /(tag)/bar%2Bbar gives the view parameter bar+bar instead of bar bar. PHP-FPM and Velocity hand the kernel the same raw address and the response cache keys are made from it, so they do not change.

Settingssite.ini [URLTranslator] DecodeOnce=disabled
New installation and upgradeoff
Switch onDecodeOnce=enabled in settings/override/site.ini.append.php, after checking links of your own that put an encoded + or % into a view parameter
For developersnew eZURI( $uri, $decode ), setURIString( $uri, $fullInitialize, $decode ) (null: follow the setting), eZURI::decodeOnce()
Testlib/ezutils/eZSysRequestURIDecodeOnceTest.php
LoveStackf435c2f91e (2018)
GuideDecoding and cleaning addresses

L33 — The double quote in IRI URL aliases

For administrators. LoveStack's URL alias cleanup strips !, dots and separators at the end of an alias, and treats " as a reserved character. Exponential has stripped those trailing characters since 2016; what it adds is the double quote: in the IRI transformation (urlalias_iri) it becomes a separator and is stripped at the ends like the others.

Settingssite.ini [URLTranslator] TrailingCleanup=disabled
New installation and upgradeoff
Switch onTrailingCleanup=enabled in settings/override/site.ini.append.php. Existing aliases stay until their object is published again; the old alias then redirects
For developerseZCharTransform::trailingCleanup()
Testlib/ezi18n/eZCharTransformTrailingCleanupTest.php
LoveStack7517c0e925 (2017)
GuideDecoding and cleaning addresses

L34 — Very large numbers no longer stop the search index

For administrators. A number in a text beyond the range of the built-in search index's integer column is stored as the limit of the column instead of stopping the indexing of the object. Each driver states its range (MAX_INT, MIN_INT: signed 32-bit for MySQL, PostgreSQL and other drivers, signed 64-bit for SQLite and MongoDB), and $db->clampInteger( $value ) keeps a value within it, also one written as a float.

New installation and upgradeon
Testkernel/search/eZSearchEngineIntegerClampTest.php
LoveStack3774a54ead (2018)
GuideNumbers in the built-in search index

For administrators. The search index leaves out the relation fields of related objects, and the relation datatypes need no recursion guard. Exponential has done the same since 2018 (EZP-27101), so there is nothing to switch and no setting; a site coming from LoveStack gets the same search results.

Testkernel/datatypes/eZObjectRelationMetaDataTest.php (documents the behaviour, a cycle of relations included)
LoveStack5c089f6250 (2017)
GuideNumbers in the built-in search index

L36 — The hide cronjob and the search index

For administrators and developers. The hide cronjob (hide.php) tells the search engine about each node it hides (in Exponential since 2018), and the content/cache event gives its listeners ( $nodeIDs, $objectIDs ) from every sender in the kernel, now also from the node's URL aliases page; a listener that takes only the node ids keeps working.

New installation and upgradeon
Testskernel/classes/runnable/HideCronjobSearchIndexTest.php, kernel/classes/eZContentCacheEventSendersTest.php
LoveStack3298b53584, 89a5a73877 (2018)
GuideCronjobs

PHP 8 review and other fixes

LoveStack carries about forty fixes for PHP 7.2 to 8.3. Each named site was reproduced on PHP 8.5 and 8.1 as a regression test; most were already handled in Exponential (which runs on PHP 8.1 to 8.5) and stay as tests that document it. Those that still failed are fixed, for every installation, with nothing to do on an upgrade:

  • the get_class and is_class template operators accept a value that is not an object without template compilation too (LoveStack e828c54709);
  • wash(email) of an empty value, the classic HTML debug report, the debug bar and ezurl / eZURI of a number or of null give no "Passing null" deprecation or warning (LoveStack 4065ed16b3);
  • eZHTTPTool copes with $_POST set to null (LoveStack 75cbb1daa2);
  • the 5.4 update script cleanupfieldvaluerelations.php skips empty relation data, and eZPostgreSQLDB::escapeString( null ) gives '' (LoveStack 1bd250d4c6);
  • a customer's orders are found from the shop's order lists, archive, customer list and dashboard when the e-mail address has a "+" (LoveStack 5a17c08bfc). A design of your own that links to shop/customerorderview can add |rawurlencode to the address in the same way.

The spell checker part of LoveStack cb8a3a1c58 was already in Exponential and is now kept by a test. Site by site, with the test of each: PHP 8 review.


Moving a site from LoveStack

A LoveStack database is close to Exponential's. Two console commands do the work that is specific to it:

./console exp:lovestack check            # read only: what the installation brings along, and what to do with it
./console exp:lovestack migrate          # dry run: prints what it would write
./console exp:lovestack migrate --apply  # records the database as Exponential's
  • check lists the database version row lovestack, LoveStack's db-schema-version row, a unique index on ezuser.login, a data_text NOT NULL DEFAULT '' column, an active legacy_2018 extension, LoveStack-only settings in settings/override, the siteaccesses and the extensions (with the Exponential name where there is one), and the mugoweb/ezpublish-legacy package in composer.json. Exit code 0: nothing to do; 1: something needs attention. --json for a machine-readable report.
  • migrate sets ezsite_data ezpublish-version from lovestack to this release's version (6.0.15stable) and records LoveStack's schema version as lovestack-schema-version (LoveStack's own row stays). It then prints the settings and extensions to change by hand. It never changes content or settings, a second run changes nothing, and a database that does not come from LoveStack is refused with a message saying so.
  • Tests: kernel/classes/expLoveStackCheckTest.php and kernel/classes/expLoveStackMigrateTest.php, on a LoveStack-shaped database built from Exponential's schema and LoveStack's schema steps 1 to 4. The same content operations (publishing, new versions, adding, moving and removing locations, copying, a new class attribute on a class with objects, the trash) give the same content as on an Exponential database, so LoveStack's data_text NOT NULL column and unique login index can stay as they are.

The full path, from backups to your own code: Moving a site from LoveStack, and the upgrade guide's Coming from LoveStack.


Already in Exponential

These LoveStack features were already in Exponential, the same or in Exponential's own way:

LoveStack featureIn Exponential
SameSite session cookies (2025)site.ini [Session] CookieSameSite, default Lax, None only with Secure; LoveStack's SameSite name is read too (above)
Passwords never silently stored as MD5PHP's default algorithm, HashType=php_default
Longer minimum and generated passwords10 and 16 characters
Increased password security (EZP-24744)yes
The date an object was trashed, and sorting the trash by it (EZP-28881)yes, same database column
WebP imagesyes
SQLite databasesExponential's own SQLite3 driver and schema handler
Log lines with siteaccess and URLyes, also under the Velocity engine
Escaped values on the database error pagethe page is rendered by eZExecution::renderErrorPage(), values escaped
eZSiteData::create()yes
"Published version" in the object informationyes
Object states (EZP-25089), the rich text editor on PHP 7yes
Empty user draft values not stored (EZP-29096)yes; a draft becomes an account only with a free login
Version details in the administrationSetup > System information and Info > About
PHP 8 supportPHP 8.1 to 8.5
Dynamic property deprecations (PHP 8.2)handled with #[AllowDynamicProperties]
Audit on by defaultExponential's own audit trail is on in every installation (settings/audit.ini Audit=enabled)

Not brought over, and why

Some of LoveStack's changes fit LoveStack's own way of working and were not needed in Exponential, or Exponential already solves the same problem differently. None of this is a judgement on the work; each item simply has a different answer here.

LoveStack itemWhy Exponential does it differently
The legacy_2018 extension (moves ezenum out of the kernel, keeps YUI 2.7.0 and the old example designs)Exponential keeps ezenum in the kernel and has replaced YUI with its own UI API. A site coming from LoveStack disables legacy_2018 (two eZEnumType classes would collide)
site.ini [HTTPHeaderSettings] SetContentLengthHeaderVelocity, FrankenPHP and the HTTP cache already send Content-Length for what they serve, after compression
update/run.php and the lovestack schema counterExponential has its upgrade SQL per release in update/database/<engine>/; exp:lovestack migrate records a LoveStack database instead
Removing the third eZSearch::search() parameter $searchTypeswould change an API that third-party search plugins use
eZPersistentObject writing '' for values that are not stringsExponential's null-safe handling keeps numbers as numbers
Rewording of debug labels, constants as array keyswording and style; Exponential changed the same files its own way
Removing the example siteaccessesExponential's installer manages its own siteaccesses
Old browser CSS, Travis, composer and README changesspecific to LoveStack's own packaging
The CSS optimiser's leading-newline trimExponential's packer works differently
JavaScript placeholder text replaced by HTML placeholdercovered by Exponential's YUI replacement
Font rewrite rule, Apache sample configurationExponential documents its own web server setup
The data_text NOT NULL DEFAULT '' column rebuilda heavy change on the largest table that Exponential does not need; a database that already has it keeps working
ezjscore cache clearing by ageExponential's cache tools (exp:cache) cover packed files
Accepting an author without an e-mail address (ezauthor)a change of behaviour rather than a PHP 8 fix; for now Exponential keeps refusing it, as every earlier release did

How it was tested

Every feature above is covered in Exponential's PHPUnit suite. Each test file runs on its own, and apart from a few tests marked as needing a database (which roll back what they write), they run without one. The tests a change needs can be run alone: see run only the tests of a change. kernel/classes/expShippedFeatureDefaultsTest.php checks that an upgraded site keeps the defaults this page names.

LoveStack's own tests/ tree was compared with Exponential's too: every test case Mugo Web added or changed since the common ancestor that covers behaviour Exponential has is in the suite, rebuilt for PHPUnit and credited. The full list is in Tests, feature by feature and LoveStack's tests in Exponential's suite.


Licence and credits

  • LoveStack is licensed under the GNU GPL version 2 (its LICENSE, with the eZ Systems copyright; composer.json: GPL-2.0). Exponential is licensed under the GNU GPL version 2 or later (GPL-2.0-or-later). Mugo Web's changes are under the same GPL version 2, so they may be combined with Exponential; the parts derived from them are distributed under the terms of GPL version 2.
  • Every feature on this page is treated as derived from Mugo Web's work, even where it was rebuilt rather than copied. Each file with derived code keeps every existing copyright notice and adds the line Portions derived from LoveStack (mugoweb/ezpublish-legacy, commit <sha>), Copyright (C) Mugo Web, GPL v2; the LoveStack commit is named in the commit message and in the 6.0.15 changelog.
  • The custom tag controls (L23) follow the design of LoveStack's custom_tags_controls editor plugin, "Copyright 2014, Mugo Web"; that notice moves with the derived parts.
  • The dual-licence wording of the original eZ Systems README can only ever be granted by eZ Systems for eZ Systems' code; it gives no rights to Mugo Web's or Exponential's code.
  • "LoveStack" is Mugo Web's name for its distribution. Exponential uses it only to describe where a feature comes from; no class, setting or product in Exponential carries it, apart from the exp:lovestack command for sites moving from it. Nothing here implies that Mugo Web endorses Exponential.

Thank you to Mugo Web for years of careful work on the legacy kernel, for documenting their schema steps so precisely that a LoveStack database can be recognised and moved, and for publishing it all as open source. This page exists because of that work.


More documents

DocumentFor
love/README.mdthe index of the detailed pages
love/GETTING_STARTED.mdeveryone: does this concern me, and where to start
love/FEATURES.mdevery feature with its default on an upgrade and on a new installation, in one table per area
love/API.mdclasses, methods, settings, template functions and console commands, for developers
love/MIGRATION.mdmoving a LoveStack site to Exponential, step by step
love/TESTING.mdthe tests of each feature and how to run them
love/TESTS-MAPPING.mdLoveStack's own test cases and where they are in Exponential's suite
love/PHP8-REVIEW.mdLoveStack's PHP 7.2 to 8.3 fixes, site by site
love/L01-callers.mdwho calls ezjscnode, and what switching on L01 changes
love/FAQ.mdcommon questions
love/ROADMAP.mdhow the work was done, and what comes next
love/CHANGELOG.mdthe releases that carry these features

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