You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A folder import no longer has to finish inside one request. After IMPORT_BUDGET seconds (20, capped at 60 percent of max_execution_time, filter living_handbook_import_time_budget) it stops between two pages, saves the rest of its work list in a transient and answers with a job id; the import screen asks again with that id until the queue is empty. Links are resolved once at the end, over every page of the run. A paused import keeps its archive download and reopens the same file, so the repository is fetched once for the whole import, not once per pass. A job belongs to the user who started it, and an archive nobody came back for is collected on the next scheduled sync.
A folder import of 20 pages or more (ARCHIVE_THRESHOLD) reads the files from one repository archive download instead of one request per Markdown file and per image. The file list still comes from the tree API, so a small import keeps the per-file path and does not fetch the whole repository for a handful of pages. A failed archive download is not fatal: the import falls back to single requests and notes why it is slow.
Fixed: a MkDocs project was imported flat, with file names as titles, whenever its mkdocs.yml configured a Python plugin. The recommended Mermaid setup writes !!python/name:pymdownx.superfences.fence_code_format, a built-in YAML tag no PHP parser resolves, so Symfony YAML threw and the whole file, nav included, was discarded without a word. The nav block is now read on its own when the file as a whole cannot be parsed. That case is not reported: the navigation arrived, which is all the import wanted from the file. Reported are the cases where the structure did not arrive, no nav, an unreadable file, no YAML reader on the server, so a flat import is never a silent surprise.
Fixed: the media endpoint described every image of an internal handbook to anyone: an attachment takes its status from its parent, the parent is published, so title, alt text and file URL were handed out in the collection and in a single read. An attachment now inherits the visibility of the handbook page it belongs to. The file in wp-content/uploads is a separate matter, the web server delivers it without asking WordPress; see the FAQ.
Translations: the German .po is complete (26 strings filled, 25 stale fuzzy entries reviewed and confirmed), and de_CH is added, derived from de_DE with the sharp s resolved to ss. Both locales ship .po, .l10n.php and the per-script JSON.
The bundled Composer libraries are moved into LivingHandbook\Vendor\ by PHP-Scoper during the release build, so a second plugin shipping league/commonmark, symfony/yaml or enshrined/svg-sanitize in another version can no longer decide which copy the import uses. Only vendor/ is prefixed, never src/; the three places that name a library class ask the new Support\Vendored, which answers with the prefixed name in a release and the plain one in a development checkout. The build fails without PHP-Scoper (LH_SKIP_SCOPER=1 overrides it for local tests) and verifies afterwards that the prefix took and the libraries still work, see bin/verify-vendor-prefix.php.
Internal: uninstall.php is covered by tests, seven of them, pinning what a deletion does and what it must leave alone; its own lookups are marked internal like every other maintenance query, so the content removal cannot be narrowed by the reader filter in a context where the plugin's hooks are registered.
Internal: the release is gated behind the full check suite, the WordPress test matrix is pinned to 6.8 and latest, and the CI actions are updated.