Skip to content

PN Scripts Press 1.1.0

Choose a tag to compare

@Petar-V-Nikolov Petar-V-Nikolov released this 18 Oct 00:06
· 3 commits to main since this release

PN Scripts Press 1.1.0 adds content in several languages (English and Bulgarian out of the box), a redirects manager, a page cache, child themes, plugin dependencies, update notices and two-factor sign-in.

Tour

Install

composer create-project pnscripts/pn-press my-site
cd my-site && php artisan db:seed && npm install && npm run build && php artisan serve

Requires PHP 8.4+. Full steps in the README.

Added

  • Languages (multilingual content): PRESS_LOCALES=en,bg. Pages, posts, categories and menus have a language; the default language lives at /, the others under /{code}. Per-language slugs and page paths, a Translate action (linked draft copy, parent page and category mapped), a language switcher (press.partials.language-switcher), hreflang + x-default links, og:locale, per-language site name, tagline, footer text and home page, per-language menus with an "every language" fallback, dates in the page language, Bulgarian front-end strings (lang/bg.json, validation, pagination), Bulgarian demo content. Helpers press_route(), press_locale_url(), App\Press\I18n\Locales. Guide: docs/multilingual.md.

  • Redirects manager (Content → Redirects): 301/302/307/308 from old addresses with hit counts; automatic 301 when a published page or post changes its address (loops and chains cleaned up). Only would-be 404s are redirected; targets must be a path or an http(s) URL.

  • Page cache for anonymous visitors that respects scheduled publishing: entries expire when the next scheduled post or page goes live and are cleared by any content, menu, settings, plugin or theme change. Pages with forms, Livewire components, flashed messages or extra cookies, signed-in users, theme previews and unknown query keys are never cached. X-Press-Cache header, php artisan press:page-cache status|clear, PRESS_PAGE_CACHE, PRESS_PAGE_CACHE_TTL, PRESS_PAGE_CACHE_STORE.

  • Child themes: "parent" in theme.json inherits views, assets, stylesheet, settings and templates. theme_asset() helper.

  • Plugin dependencies: requires.plugins, requires.php, requires.extensions (themes: PHP and extensions). Activation, deactivation and uninstall respect them; dependencies boot first; a plugin whose dependency vanished is skipped and reported.

  • Update notices for the core (GitHub latest release), plugins and themes (update_url): php artisan press:check-updates, scheduled daily; badges in the admin. Nothing is downloaded or installed.

  • Two-factor sign-in for the admin: profile page with authenticator app and recovery codes; PRESS_REQUIRE_2FA.

  • Larastan (PHPStan level 5) in CI, composer analyse.

Security

Review of the 1.1 code paths (sign-in and 2FA, page cache keys, uploads, plugin loading, languages, redirects):

  • Stored XSS from editors closed: post bodies and Text blocks are sanitised on output (Symfony HtmlSanitizer via Filament), so an editor's HTML can no longer run scripts for visitors or signed-in admins.
  • SVG uploads with scripts, event handlers, javascript: links, foreign HTML, entities or external references are refused and deleted (they are served from the site's own address).
  • Trusted hosts: outside local/testing only the APP_URL host and its subdomains are answered, so a forged Host header cannot fill the page cache or poison absolute links. Make sure APP_URL is your real address in production.
  • Redirect targets are limited to site paths and http(s) URLs (no //host, no script URLs); the locale sent by forms is accepted only when it is a configured language; language codes in PRESS_LOCALES are validated.

Changed

  • symfony/yaml 8.1.9 (CVE-2026-109413).
  • composer.json now requires PHP ^8.4 (the 1.0 lock file already needed it through Symfony 8.1; composer create-project on PHP 8.3 now fails with a clear message instead of a dependency error).
  • Contact Form plugin 1.2.0 (sends the page language so errors are translated; strings translatable), SEO Sitemap plugin 1.2.0 (every language, xhtml:link alternates).
  • Core views use press_route() / $model->url() instead of route('blog') etc. Theme overrides that still call route('blog') keep working but always link to the default language.
  • Larastan baseline down from 41 to 19 entries (content models are typed).

Upgrade notes (from 1.0.0)

  • Back up the database, then composer install and run php artisan migrate: 2FA columns on users, locale + translation_group on pages/posts/categories (existing rows get the default language), slug/path uniqueness becomes per language, locale on menus, and the redirects table. All migrations are reversible.
  • Nothing changes for visitors until you list a second language: without PRESS_LOCALES the site stays single-language. To add Bulgarian set PRESS_LOCALES=en,bg, run php artisan config:clear (and route:cache if you cache routes), then translate items with Translate.
  • Production: APP_URL must match the address visitors use (trusted hosts).
  • Custom theme views: replace route('blog'), route('posts.show', $post->slug), route('categories.show', …) and url('/') with press_route('blog'), $post->url(), $category->url() and press_locale_url('/'), and add @include('press.partials.language-switcher') to your header. Wrap fixed texts in __().
  • The page cache is on when APP_DEBUG=false. Run php artisan press:page-cache clear after deploying view or theme files, or set PRESS_PAGE_CACHE=false.
  • Copy the bundled plugins/contact-form and plugins/seo-sitemap folders over yours (versions 1.2.0); they upgrade on the next request.
  • Add the Laravel scheduler to cron for daily update checks: * * * * * php artisan schedule:run.