Skip to the content
Documentation

Help center

Help for Developers

Build on it: extensions, templates, settings, the APIs, the command line and upgrades.

5997 pages

Start here

Read these pages in this order.

  1. Develop with Git: grow from user to developer The recommended way to build websites with Exponential. Install the kernel and every se7enxweb extension as...
  2. Extension development: the book (start here) A complete book on growing from user to builder, extension developer and theme developer with Exponential:...
  3. Add a database table A migration that creates a table of the site's own on every engine from a share/db_schema.dba definition, w...
  4. AI, agents and agentic: start here The landing page for people who use AI with Exponential and for people who build agents and agentic workflo...
  5. Ecosystem: start here The landing page for the Exponential Ecosystem - the greater Exponential world within the PHP stack, its us...
  6. Integrators: start here The landing page for system integrators and integration developers who connect Exponential with CRM, ERP, P...

Good to know

  • Migrations

    The start of everything about migrations in Exponential 6.0.15 - schema and content changes written once as files under version control and applied to every installation of a site in the same order, with a caption…

  • Migrations: a first PHP migration, step by step

    In this tutorial you write two PHP migrations for a site: one creates a table exp_news_note with a first row, the other publishes a folder "News" below the content root and notes it in the table. You check them, look at…

  • Add a database table

    A migration that creates a table of the site's own on every engine from a share/db_schema.dba definition, writes a first row, and drops it again in down() - with the dry run, the run, the checks and the rollback.

  • Testing migrations: check, simulate, diff and CI

    Four layers of tests for migrations - the lint without a database, the dry run, the simulation with a diff on PostgreSQL or SQLite, and a PHPUnit test on a throwaway SQLite database - and how to run them in CI.

  • Deploying with migrations: CI/CD and GitHub Actions

    Run migrations as part of every deploy - the order of the steps, a complete GitHub Actions workflow that checks pull requests and deploys over SSH, the exit codes a pipeline acts on, the installation lock, and runs…

  • Team workflow with git: branches, conflicts and order

    How several developers write migrations on branches without stepping on each other - timestamps and order, requires for real dependencies, two migrations with the same timestamp, rebasing, renaming only before a merge…

Search by topic

Each button lists the pages of one topic for Developers.

What changed in the source code most recently: the main branch of se7enxweb/exponential, read from its public feed by this server.

Hide merge commits

  1. Updated: The service worker leaves the shop to the browser, so a bask… (opens in a new window) se7enxweb ·
    Message
    Updated: The service worker leaves the shop to the browser, so a basket update shows the new quantity
    
    The basket, its updates and the checkout follow the visitor's session, which
    lives in an HttpOnly cookie the worker cannot see. Handled by the worker, the
    round trip of a basket update (post, update, back to the basket) came back
    showing the basket as it was before the change, although the new quantity
    was stored. /shop joins /admin, /editor and /user in the paths the worker
    never handles, and a test keeps those four on the list.
    fa5a36b217
  2. Updated: SVG files kept by the file and media datatypes are stored on… (opens in a new window) se7enxweb ·
    Message
    Updated: SVG files kept by the file and media datatypes are stored only sanitized
    
    An SVG uploaded through the binary file or media datatype is stored under
    storage/original/image/, the directory every shipped web-server
    configuration serves as files, but only the image datatype ran it through
    the SVG sanitizer. Such a file could carry script that runs in the site's
    origin when it is opened directly; the Content-Security-Policy sandbox
    header of the shipped configurations was the only barrier.
    
    - expSvgSanitizer::sanitizeStoredUpload() sanitizes a stored upload in
      place when it is an SVG by its name, the uploader's name or its content,
      and refuses a .svg that is no SVG.
    - eZHTTPFile::store() calls it for every browser upload; the file and media
      datatypes call it for their file imports (insertRegularFile) and package
      imports. A refused file is removed and the upload fails.
    - file.ini FileExtensionBlackList[] also refuses html, htm, xhtml and xht,
      as defence in depth for servers that hand out storage/original as files.
    - The security-hardening guide (English and German) states that var/ must
      never be served statically beyond the shipped allow-list.
    
    Reported by 0xpack.
    3b0fc18474
  3. Updated: The cron setup takes out the blocks of installations that ar… (opens in a new window) ·
    Message
    Updated: The cron setup takes out the blocks of installations that are gone
    
    installcrontab.php --add (and the installers' cron step) kept every other
    installation's block, also of folders that no longer exist. An installation
    built in a fresh folder and then moved into place (a demo rebuilt every two
    hours) left one block per build: a crontab of 185 blocks whose jobs started
    every minute, failed at their cd and mailed the failure.
    
    expCrontabSetup::add() now takes those blocks out on the way (pruneGone(): a
    block whose root folder is gone; the installation being written and unfinished
    blocks stay) and names them in its result. The installer crontab guide says
    so, and how a build-and-move installation writes its block from the folder it
    is served from. Covered by two new tests.
    cd2c022c8f
  4. Updated: A member's own account never shows Meta Data (opens in a new window) ·
    Message
    Updated: A member's own account never shows Meta Data
    
    A member who edited their own account (user/edit, content/edit of their user
    object) got Meta Data and the other attributes of the user class's "meta"
    category in the edit form of every design, and so did the sign-up form of
    designs that list every attribute. They are editorial settings and never a
    member's business.
    
    kernel/content/attribute_edit.php now takes them out of the edit list right
    after it is fetched (expUserOwnAccountAttributes): for a user account edited by
    its own user or a visitor signing up, the "meta" attributes are neither shown,
    validated, read nor stored. An editor who edits another person's account still
    gets them. Covered by a DB-less test.
    434c588e05
  5. Updated: The sign-up form shows only what a new member fills in (opens in a new window) ·
    Message
    Updated: The sign-up form shows only what a new member fills in
    
    The user/register form of the standard design rendered every attribute of the
    user class the way the editor does: a "User account" heading above the account
    fields, the account's empty User ID and its status ("disabled"), and the image
    block with "There is no image file", a remove button and the image tools before
    the upload field.
    
    The form now renders its fields through design/standard/templates/user/
    register_attribute.tpl: no attributes of the class's "meta" category, no
    heading for the user account, and an image as one plain upload field with a
    field for its description. The account edit template takes register=true() to
    leave out the User ID and the account status (content/datatype/edit/ezuser.tpl,
    standard and admin4); the editor's form is unchanged. Its labels reuse texts every
    catalogue already translates ("optional", "Alternative image text").
    b7db543550
  6. Updated: The service worker keeps pages styled after the packer cache… (opens in a new window) ·
    Message
    Updated: The service worker keeps pages styled after the packer cache is cleared
    
    Packed stylesheets and scripts carry the newest source file's time in their
    name ([Packer] AppendLastModifiedTime), and clearing the packer cache deletes
    every packed file. A page the service worker had stored still named the old
    file, so the browser got a 404 and showed the page without styles until the
    next reload; on phones, where the worker answers almost every visit, this
    happened often.
    
    The worker now keeps the last good copy of each packed stylesheet and script
    under its name without the time. When a packed file answers 404, that copy
    stands in and the stored pages are dropped, so the next visit loads the page
    that names the new file. A copy is written only when a new version appears.
    
    The cache version moves to exp-nav-v6, so browsers drop every page stored by
    v5 on their next visit, including those that already name a deleted file.
    c5b96f69d1
  7. Added: An Exponential Documentation section in the README that links … (opens in a new window) ·
    Message
    Added: An Exponential Documentation section in the README that links to doc.exponential.earth
    
    The section says how the documentation portal saves time and money on a project, and gives starting points for common needs: editing content, layouts, users and access, installation, concepts, configuration, templates, features, the reference, extensions and the help center. Every link was checked against the live site.
    The heading of the notice for new users is capitalized.
    d5263e7883
  8. Updated: The documented INI load order matches the kernel, in English… (opens in a new window) ·
    Message
    Updated: The documented INI load order matches the kernel, in English and German
    
    The configuration guide listed the active extensions below the siteaccess and
    an extension's siteaccess directory above it. eZINI reads them the other way:
    after the defaults come the extensions a siteaccess activates for itself
    (ActiveAccessExtensions[]), the extension siteaccess directories, the
    siteaccess, the extensions in ActiveExtensions[] and settings/override. An
    active extension therefore wins over settings/siteaccess//.
    
    - CONFIGURING: the layer table in that order, the extension listed first wins
      inside a layer (not the last one), and the advice for a siteaccess value
      that has to beat an extension.
    - The settings page guide, the per-site settings of extensions, the
      after-installing order note, the students' mistakes table, the book
      comparison and the multisite extension list say the same.
    - The 6.0.15 changelog names the correction.
    0e113e81b7
  9. Merge branch 'expcomponents-switch' into expcomponents-docs (opens in a new window) ·
    Message
    Merge branch 'expcomponents-switch' into expcomponents-docs
    
    # Conflicts:
    #	share/filelist.md5
    811ec3dc2c
  10. Updated: The mail address refusal test runs only where the mail fork … (opens in a new window) ·
    Message
    Updated: The mail address refusal test runs only where the mail fork is installed
    
    ezpMailMessageIdTest MI-05 checks a behavior of se7enxweb/expcomponents-mail
    1.10.2. A vendor/ that still holds the upstream zetacomponents/mail 1.10.1,
    as an installation does until its next composer update, does not refuse the
    address, so the test now skips there instead of failing. A fresh install,
    as CI makes, has the fork and runs it.
    1365318ef3

Showing 1–10 of 55 commits

Recently updated

Free documentation: use it to help yourself and others

This help is free documentation, licensed under the GNU Free Documentation License 1.3 or later. You may use it, share it and improve it:

  • Study it Read any page as often as you like, for any purpose.
  • Copy it and share it Give pages to other users, on paper or as files. Keep the copyright notice, the license notice and a copy of the license with every copy.
  • Translate, adapt and improve it Share your version under the same license, with the original notices and a note of what you changed.
  • Cite it Refer to a page by its title and its address in the help, or its file in the doc directory.
  • Contribute fixes back Use "Edit on GitHub" on any page. Changes are accepted under the same license, so they stay free for everyone.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x