Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Core Laravel Package

redaxo/core

REDAXO is an easy-to-learn, highly extendable PHP content management system and framework, trusted since 2004. Build content from custom modules with full control of any input and output, multilingual support, and workflows that adapt to you, backed by a friendly community.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: redaxo/core is not a Composer library you require into a Laravel app. It is a standalone PHP 8.3+ CMS that ships its own request pipeline, autoloader, addon lifecycle, and admin UI. "Using this package" means either building sites on REDAXO or writing addons for it — not importing rex_* classes into an Eloquent model. Decide which of those two you are doing before anything else.

Fastest path to a running system

  1. Grab a release zip from github.com/redaxo/core/releases and extract it into a webroot — that's the supported install path. Don't try to assemble it from the repo unless you intend to contribute.
  2. Open /redaxo/ in the browser and run the setup.
  3. Log in, open the Installer addon, and install demo_base (the "Basisdemo"). It is the only demo fully translated to English and it documents modules, templates, articles, media manager and cronjobs in situ. This is your primary onboarding artifact.
  4. Only if you are developing on core/addons: git clone, composer install, then docker-compose up -d (override port with REDAXO_PORT=8080).

Where to look first

Need Look at
Request lifecycle redaxo/src/core/boot.php, redaxo/src/core/backend.php
API reference friendsofredaxo.github.io/phpdoc
Conceptual docs (mostly German) redaxo.org/doku/5.x
Recipes friendsofredaxo.github.io/tricks
Changelog / BC breaks redaxo/src/core/CHANGELOG.md

First use case that pays off: register an extension point instead of forking a template. The canonical smoke test is a boot.php in a throwaway addon that hooks OUTPUT_FILTER and rewrites a string in the rendered frontend. If that works, your addon bootstraps correctly and you understand the extension model — which is 80% of day-to-day REDAXO work.

Implementation Patterns

Addons are the unit of composition. A minimal addon is a directory under redaxo/src/addons/<name>/ with a package.yml and a boot.php. Lifecycle hooks are plain files: boot.php (every request), install.php, update.php, uninstall.php. boot.php is included on both frontend and backend requests — guard side effects with rex::isBackend().

// boot.php
rex_extension::register('OUTPUT_FILTER', static function (rex_extension_point $ep) {
    return str_replace('</body>', '<script src="/assets/myaddon/track.js"></script></body>', $ep->getSubject());
});

Extension points over patching. Everything meaningful fires an EP: PACKAGES_INCLUDED, ART_INIT, SLICE_SHOW, MEDIA_MANAGER_TYPE, STRUCTURE_*, BACKEND_PAGE_*. Find the right one via rex_extension::register call sites in core rather than editing core files — core upgrades are frequent and will eat your patches.

Backend UI: don't hand-roll HTML. rex_form (base class for forms), rex_list (paged/sortable tables), rex_fragment (view partials), rex_view (page shell), rex_be_controller::includePath + rex_be_page (nav registration) are the standard toolkit. This is REDAXO's analogue to Blade + resource controllers; it is dated but it produces consistent admin screens for free.

Data access is rex_sql, not an ORM. Prepared statements, manual hydration:

$sql = rex_sql::factory()->setQuery('SELECT * FROM '.rex::getTable('myaddon_log').' WHERE level = :lvl', ['lvl' => 'error']);

Schema management uses rex_sql_table::ensure() — an idempotent "make the table look like this" declaration that runs in install.php/update.php. There is no migration runner: version bumps are detected by comparing the version in package.yml against the installed version, which triggers update.php. Treat update.php as your migration file and keep it re-runnable.

Content reads. rex_article::get($id), rex_category::get($id), rex_article_slice, rex_media, rex_media_manager::getUrl($type, $file). Results go through an instance pool, so repeated get() calls are cheap — that makes it idiomatic to fetch the same article several times in a template rather than threading objects around.

Frontend templating is placeholder substitution, not a template engine. Templates and modules contain tokens like REX_ARTICLE[], REX_VALUE[1], REX_MEDIA[1], REX_LINK[1], REX_MEDIALIST[1], REX_HTML_VALUE[1], which core replaces before output. This is the biggest conceptual shift from Laravel: there is no view layer to learn, but also no control flow, no escaping guarantee, and no IDE support. Keep logic in the module's PHP input code (runs in backend, produces the form) and output code (runs on frontend, emits markup), and keep output escaping explicit.

AJAX endpoints: extend rex_api_function, register your function name, and it becomes callable through the standard backend API route with permission checks wired in — better than hand-rolled ?action= handlers.

Scheduling: use the cronjob addon rather than sleep/webhooks; jobs are registered in PHP and get a real admin UI and logging.

Escaping and CSRF are manual.

echo rex_escape::html($value);
echo '<input value="'.rex_escape::htmlAttr($value).'">';
$token = rex_csrf_token::factory('myaddon_save')->getToken(); // render into form
if (!rex_csrf_token::factory('myaddon_save')->validate()) { /* reject */ }

Every write action — including anything you add — needs both a CSRF check and a rex_perm::register() permission. Recent releases show the core team is actively hunting missing checks in exactly these spots; assume a reviewer or an advisory will find yours if you skip them.

Quality gate for addon work: composer check (cs + phpstan + psalm + phpunit + taint). Taint analysis is included — notable, and worth running against addon code that touches $_GET/$_POST, since it catches unescaped output paths.

Gotchas and Tips

Licensing discrepancy. The repo metadata reports NOASSERTION, while the README badge and LICENSE.md say MIT. Before shipping commercially, read redaxo/src/core/LICENSE.md in the exact tag you deploy and record it — don't rely on the GitHub API field.

Security patch cadence is the real operational cost. The 5.21.x line carries a steady stream of GHSA advisories — CSRF gaps in metainfo and be_style, stored XSS in link/media widgets, permission bypasses in structure/history and structure/version, and a critical session-forgery issue in structure/history fixed in 5.21.4. You must plan to update promptly, and you should keep addons you don't use uninstalled, not merely deactivated. Pin the version, watch releases, and treat structure/history and backup as high-risk addons.

Debugging cache is invisible and hostile. REDAXO caches aggressively (config, addon list, media manager types, instance pool). After changing package.yml, addon registration, or a media manager type, the symptom is "my code isn't running." Call rex_delete_cache() from a console command (redaxo/bin/console) and re-test before you debug logic. One released bug was literally a parallel cache delete producing "No clang found" — expect cache-layer weirdness to masquerade as logic errors.

Instance pool caches misses. rex_article::get() with a nonexistent ID was caching nothing until 5.21.5, so it hit the DB on every call. On older versions, guard hot loops with your own existence check.

rex_sql_table::ensure() can churn. On mixed MySQL/MariaDB fleets, column types and defaults were historically normalized differently, causing ensure to rewrite the column on every request. Fixed in 5.21.5 — on earlier versions, watch for unexpected DDL on page load. Also be aware that foreign keys could be read from same-named constraints in other databases on the same server (also fixed in 5.21.5).

Safe mode is a footgun. Toggling it via the safemode query parameter requires a valid CSRF token since 5.21.5; older versions let a crafted link flip it. Know that safe mode disables addons — never debug "why is my addon dead" without checking it.

The directory protection check runs requests. A daily filesystem check could trip fail2ban and lock backend users out (fixed to one directory per day, plus a use_directory_protection_check config option). If you see mysterious backend lockouts on a monitored host, this is a candidate.

Docs are German-first. The API PHPDoc and Tricks site are usable, but conceptual documentation, changelogs, and much community knowledge are in German. Budget for that; the Slack (redaxo.org/slack) is the practical escape hatch and core devs answer there. The README explicitly asks non-German speakers not to be deterred — take it up on that.

Composer is not your dependency manager for addon code. Addons can vendor libraries, but the autoload boundary is the addon, not the project. Don't assume a project-root composer.json change propagates into addon use statements; declare and load per addon.

Where the extension model breaks down. EPs are string-keyed and untyped; $ep->getSubject() can be a string, array, or object depending on the point, and IDE support is nil. Document the expected subject type next to each register() call, or you will spend afternoons on str_replace being handed an array.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table