This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
block_peek is a REDAXO 5 backend addon (PHP 8.2+, REDAXO ^5.17). It replaces the default slice output in the article-edit view with a zoomed-down iframe rendering the slice as it would appear in the frontend. The README is in German.
# PHP deps (matches the GitHub release workflow)
composer install --no-dev --optimize-autoloader
# Build the JS/CSS bundle into ./assets/ (also syncs version + cleans assets/)
npm run build
# Watch mode (no sync)
npm run watch # alias: npm run dev
# Watch + rsync built assets into REDAXO's public/assets/addons/block_peek/
# (path is hardcoded as ../../../public/assets/addons/block_peek/, so this only
# works when this repo is checked out at <redaxo>/src/addons/block_peek)
npm run dev:sync
# Sync version from package.yml -> package.json (also runs as part of prebuild)
npm run version:syncThere is no test suite, no PHP linter, and no JS linter wired up. .stylelintrc.json and .prettierrc exist but are not invoked by any npm script — run npx stylelint / npx prettier directly if needed.
package.yml is the single source of truth for the addon version. vite.config.js reads it directly, and scripts/sync-version.js (run via prebuild) copies it into package.json. When bumping the version, edit package.yml and let the build sync the rest. Also update CHANGELOG.md.
boot.phpregisters a late handler on REDAXO'sSLICE_BE_PREVIEWextension point (only wheninactiveconfig is not|1|, the user is logged in, and we are in the backend).lib/Extension.php(FriendsOfRedaxo\BlockPeek\Extension::register) is the EP callback. It reads slice params from the EP, instantiates aGenerator, wraps the result in<iframe srcdoc="...">, and replaces the EP subject. No HTTP round-trip — the preview HTML is inlined assrcdoc, which is why loading is instant.lib/Generator.phpbuilds the inner HTML:- Cache key =
md5(articleId + sliceId + updateDate + revision), stored via SymfonyFilesystemAdapterin the addon's cache path. Cache mode (auto/active/inactive) lives in addon config;autofollows REDAXO debug mode. - Renders the slice via
rex_article_content::getSlice(). - Wraps it in the user-configured template (settings page), substituting the
{{block_peek_content}}placeholder. - Injects
assets_head/assets_bodysnippets, sets<html lang>from the clang. - Inlines
assets/BlockPeekPoster.jsinto<script>with two placeholders replaced:BLOCK_PEEK_PLACEHOLDER_SLICE_ID,BLOCK_PEEK_PLACEHOLDER_MAX_HEIGHT. This is what posts the iframe height back to the parent. - Replaces REDAXO vars (
REX_MODULE_ID,REX_MODULE_KEY,REX_SLICE_ID,REX_CTYPE_ID, common vars,redaxo://links), then writes the template to a temp file in the cache dir andincludes it bound to therex_article_contentso$thisworks inside template PHP. - Fires the
BLOCK_PEEK_OUTPUTextension point so projects can post-process. - Optional
force_feconfig flipsrex::setProperty('redaxo', false)so frontend-only code paths run.
- Cache key =
Source in assets-src/, built into assets/ (committed) by Vite. Vite externalizes jquery and bootstrap because REDAXO provides them.
BlockPeek.jsruns in the REDAXO backend page. Two responsibilities:- Iframe sizing: listens for
postMessage({type:"resize", id, height})from each iframe and sets the wrapper's height toheight * zoomFactor. - Async slice edit/save on
rex.page === "content/edit": intercepts edit/save/apply clicks, fetches viaXMLHttpRequest-marked requests, and swaps the.rex-sliceDOM in place — no full page reload. It also handles back/forward navigation viapopstateand re-runs CKEditor'supdateSourceElement()before serializing the form (this matters; see CHANGELOG 1.1.1).
- Iframe sizing: listens for
BlockPeekPoster.jsruns inside the iframe (via the inlined<script>fromGenerator::getTemplate). It uses aResizeObserverondocument.bodyto post heights up. It also stubshistory.replaceStateto swallow errors —srcdociframes can't use the History API, and frontend code that calls it would otherwise throw (CHANGELOG 1.1.0).
pages/index.php— wrapper that callsrex_be_controller::includeCurrentPageSubPath().pages/settings.php— admin-only config form built withrex_config_form. Fields:template,assets_head,assets_body,cache,cache_ttl,inactive,iframe_min_height,iframe_max_height,iframe_zoom_factor,force_fe.- The "docs" subpage is just
README.mdrendered viasubPathinpackage.yml.
composer.json uses a classmap on lib/. After editing classes there, the GitHub release action runs composer install --no-dev --optimize-autoloader to regenerate it; locally you may need composer dump-autoload if you add new classes.
.github/workflows/publish-to-redaxo.yml runs on GitHub Release publish: installs prod composer deps, zips the repo (excluding assets-src/, scripts/, node_modules, dotfiles, *.json package files, vite.config.js, etc. — see the workflow for the full list), uploads the zip to the release, and pushes to MyREDAXO via FriendsOfREDAXO/installer-action. The installer_ignore list in package.yml mirrors most of these exclusions for the in-REDAXO installer path.
Build artifacts under assets/ ARE committed and shipped — do not add them to .gitignore.