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: URL map targets resolve as the siteaccess serves them, below… (opens in a new window) ·
    Message
    Updated: URL map targets resolve as the siteaccess serves them, below its PathPrefix
    
    A target path of a URL map row is the address a visitor uses. On a siteaccess
    with a PathPrefix (site.ini [SiteAccessSettings]) the page /recipes is stored
    as /fit-healthy/recipes, so a row "/about-us.html,/recipes" was planned as a
    broken target although the page answers at /recipes.
    
    - The planner looks a target path up below the PathPrefix of the row's
      siteaccess first (not when its first element is one of PathPrefixExclude[],
      as storing an alias does), then as it is, so a path written with the prefix
      or one outside it still resolves; a row of every siteaccess has no prefix
    - The export writes a URL alias stored below the prefix of the siteaccess
      (the -s filter, else the default siteaccess) the way visitors use it,
      without the prefix and with that siteaccess in its column, so importing the
      file again stores it at the same place
    - expUrlMapKernelEnvironment::unprefixedPath() and pathPrefix()
    - Test: targets and the export form below a PathPrefix, without a database
    a95101d160
  2. Added: Import, export, history and undo of URL maps in the administra… (opens in a new window) ·
    Message
    Added: Import, export, history and undo of URL maps in the administration
    
    The URL translator and the wildcards get the screens for URL maps, in the
    admin4 and admin designs:
    
    - Import a URL map (content/urlimport): a file uploaded or pasted, its
      format found or chosen, the siteaccess and language of bare paths, the
      conflict policy and the old hosts. The preview lists every row with its
      state as a filter (new, changed, unchanged, duplicate, conflict, broken
      target, unknown host, not importable), a tick for each row that can be
      imported, unknown hosts mapped to a siteaccess and the file planned
      again, a dry run that writes nothing, the plan as CSV or JSON, and the
      import as one batch. The file and the plan stay on the server for the
      user who uploaded it, at most a day (expUrlMapImportSession); the forms
      post only the decisions of the rows shown, never the plan.
    - Import history (content/urlimporthistory): every import with who, when,
      the file, the counts and the state; one import's entries a page at a
      time, and Undo, which lists the entries changed since the import and
      keeps them unless ticked (expUrlMapImporter::changedSince()).
    - Export (content/urlexport) as a download in every format, and the list
      of redirects with a query or a status (content/urlredirects), with
      removing one or the ticked ones.
    - The policy function content/urltranslator_import for importing and
      undoing; the export and the redirects stay under content/urltranslator.
      Importing and undoing ask "Verify it's you" ([ReauthGroup_system]).
    - Buttons Import, Export, Import history and Redirects on the URL
      translator and the wildcards pages, shown by policy.
    - The wildcard pages show a temporary forward wildcard as "Temporary
      redirect (302)" instead of "Undefined", and the filter Redirecting
      lists both forward types (eZURLWildcard::fetchFilteredList() takes a
      list of types).
    - The strings in every administration catalogue, the context help, the
      guide "URL maps:…
    2d794ad83a
  3. Updated: Redirects of URL map imports answer for any old address, and… (opens in a new window) ·
    Message
    Updated: Redirects of URL map imports answer for any old address, and aliases follow the PathPrefix
    
    Found by importing a test map on a site whose siteaccess has a PathPrefix:
    
    - A redirect of exp_url_redirect runs the error module, as a moved URL alias
      or wildcard does, so an old address that is no module of the site (most of
      them) redirects instead of answering 404
    - A URL alias imported for a siteaccess with a PathPrefix is stored below the
      prefix, unless PathPrefixExclude[] names its first element, which is where
      the siteaccess looks it up; the page conflict check looks there too
      (expUrlMapEnvironment::aliasPath())
    - The BC note and the changelog say so; planner tests for the prefix
    aee5f8721a
  4. Updated: URL map commands and temporary folders follow the kernel rules (opens in a new window) ·
    Message
    Updated: URL map commands and temporary folders follow the kernel rules
    
    - The spreadsheet classes make their temporary folder with eZDir::mkdir(),
      so it gets the installation's directory mode
    - The exp:url commands' shared base has the run() every kernel command has
    - The wildcard pages keep their texts: the badge of the temporary forward
      wildcard comes with the administration's URL map screens, together with
      its translations in every admin catalogue; the changelog says so
    add21407bc
  5. f0c4ab5273
  6. Added: Import, export and undo of URL maps, and redirects checked on … (opens in a new window) ·
    Message
    Added: Import, export and undo of URL maps, and redirects checked on the full request
    
    The second part of importing and exporting the URL translator and the URL
    wildcards. A URL map is planned row by row, imported as one batch that can be
    undone, and exported again in every format; what a global URL alias cannot
    hold goes into a new table of redirects that is checked before the aliases.
    
    - exp_url_redirect and expUrlRedirect: redirects checked once per request on
      the address asked for, before the URL aliases and wildcards (in the kernel's
      request loop, so also under Velocity): an old address with a query (the
      order of its parameters ignored), a temporary status (302, 303, 307) or
      308, a target with a query or on another site; per siteaccess or for all;
      node targets follow the node; the old query is not carried over. Read from
      a cache file beside the wildcard cache, reset per request
    - expUrlMapPlanner and expUrlMapPlan: every row classified as new, unchanged,
      changed, duplicate, conflict (a page's own address, a module address, the
      front page), broken-target, unknown-host or not-importable, with where it
      goes, the siteaccess from the host through the siteaccess matching (or a
      mapped old host), the language, per-row decisions and a JSON or CSV report
    - expUrlMapImporter: applies a plan in one transaction with the conflict
      policy skip or overwrite, records every row it writes before and after in
      exp_urlmap_batch and exp_urlmap_batch_item, and undoes a batch exactly (rows
      changed since are kept unless forced); clears the caches; audit events
      content.urlalias.import and content.urlalias.import_undo
    - expUrlMapExporter: global URL aliases (optionally the aliases of nodes),
      wildcards and redirects as rows for every writer; an export imported again
      is unchanged
    - Commands exp:url:import, exp:url:export, exp:url:batches, exp:url:undo;
      the upgrade step 6.0.15-url-map with the tables in the kernel schemas and
      the 6.0.15 update files
    - A te…
    9abefc5714
  7. Updated: The trash list wraps long text and scrolls instead of cuttin… (opens in a new window) ·
    Message
    Updated: The trash list wraps long text and scrolls instead of cutting off its Restore column
    
    A long unbroken name in the Date trashed column (a script name such as
    cli hmeb_trash_help_ebooks_of_untranslated_manual_editions.php) made the
    table wider than its card, which cut off the last column with the Restore
    buttons. Cells now break such text anywhere and the list scrolls sideways
    if it still does not fit, in both admin designs.
    821ea9bd2b
  8. Updated: URL map files read .ods, keep temporary redirects and read A… (opens in a new window) ·
    Message
    Updated: URL map files read .ods, keep temporary redirects and read Apache Redirect as a prefix
    
    Follow-ups of the URL map files, as decided after their first part.
    
    - Temporary redirects keep their status: the kinds redirect-temporary and
      wildcard-forward-temporary (302), and an optional seventh column status for
      308, 303 or 307 of the same kind; a file without the column reads as before.
      The Apache and nginx readers read 302, 303 and 307 as temporary kinds with
      their status instead of 301 with a note, and the writers write each row's
      status
    - Apache Redirect /old /new is read as Apache answers it: the path as a
      redirect plus the wildcard /old/* -> /new/{1} for everything below it
    - .ods is read too (expSpreadsheetReader::readOdsFile(), expUrlMapOdsReader):
      repeated rows and columns, spaces, tabs and line breaks in cells; a ZIP file
      is recognized as .ods by its mimetype
    - The spreadsheet classes put their temporary files in the installation's
      cache directory (var//cache/spreadsheet, else var/tmp), never the
      system's temporary directory, so they work under open_basedir
    - Specification (English and German), changelog, tests: an .ods saved by
      LibreOffice, .ods cells of every kind, every redirect status through every
      format and back
    6e7d7bb5ca
  9. Added: Readers and writers for URL map files of the URL translator an… (opens in a new window) ·
    Message
    Added: Readers and writers for URL map files of the URL translator and wildcards
    
    A URL map lists old addresses and where each goes (old_url, new_url, kind,
    siteaccess, language, note), as the first step of importing and exporting
    global URL aliases and URL wildcards. This adds the file part only; nothing
    here touches the database.
    
    - expUrlMapRow: one mapping, with the kinds redirect, alias,
      wildcard-forward, wildcard-direct (or empty for automatic), the
      normalization of old and new addresses (scheme and host, slashes, dot
      segments, trailing slash, percent-encoding, node references) and the
      problems that keep a row from being imported, with its line
    - Readers for CSV (delimiter sniffing, byte order mark, UTF-16 and
      Windows-1252 input, quoted multi-line fields, English and German column
      names), JSON (exp-url-map/1), .xlsx, Apache (Redirect, RedirectMatch,
      RewriteRule with host and query conditions) and nginx (rewrite, return
      in exact and regular expression locations, map); simple regular
      expressions become wildcards, other rules rows that are not importable
    - Writers for CSV, JSON, .xlsx, .ods, Apache and nginx; internal kinds and
      node targets go into #exp: comments that the readers read back
    - expSpreadsheetReader and expSpreadsheetWriter: the table part of .xlsx
      (read and write) and .ods (write) with ZipArchive, no new dependency
    - expUrlMapFormats chooses reader and writer by name, extension or content
    - The specification of the file formats in English and German, and the
      6.0.15 changelog entry
    - DB-less tests with fixtures for every format, round trips through every
      writer, 10,000 rows, and a LibreOffice conversion where it is installed
    fea55e693c
  10. Updated: A character reference shown as text in a code block is no lo… (opens in a new window) ·
    Message
    Updated: A character reference shown as text in a code block is no longer decoded twice
    
    The online editor's literal handler decoded the named references first and the numeric ones after, so
    "Ӓ", the text "Ӓ" in a code block about character references, became "Ӓ" and then
    the character itself. The numeric references are decoded first now; an escaped one stays text.
    f33289c6c6

Showing 21–30 of 49 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