Eight merges landed in laravel/framework targeting the 13.x branch. The headliner is a new @fonts Blade directive backed by a full Vite font runtime. The rest of the batch splits between one functional addition, one test fix, and four PHPDoc corrections that close gaps static analysers have been hitting for a while.
@WendellAdriel merged PR #59584, adding a @fonts Blade directive and a ViteFonts class that reads the font manifest your Vite plugin generates.
Drop it in your layout and every configured font gets a preload <link> plus an inline <style> block containing the @font-face rules and CSS variables:
1<!DOCTYPE html> 2<html> 3<head> 4 @fonts 5 @vite('resources/js/app.js') 6</head> 7<body> 8 {{ $slot }} 9</body>10</html>
Pages that only need a subset of fonts can filter by family alias:
1{{-- single family --}}2@fonts('sans')3 4{{-- multiple families --}}5@fonts(['sans', 'mono'])
Only the @font-face rules, CSS variables, and preload links for the requested families are included. The AddLinkHeadersForPreloadedAssets middleware picks up font preload entries automatically for HTTP/2 server push, and CSP nonce support is wired in throughout.
Apps already using a Vite font plugin that generates a font manifest will get the most out of this immediately. Everyone else has a clean path to adopt it when the accompanying Vite plugin side ships.
@jnoordsij merged PR #59859, adding support for PHP 8.6's native SortDirection enum in collection and Arr sort methods.
Instead of passing a boolean, sort calls can now express intent explicitly:
1use SortDirection;2 3$collection->sortBy('name', descending: SortDirection::Descending);4$collection->sortBy('name', descending: SortDirection::Ascending);5 6Arr::sort($array, descending: SortDirection::Descending);
Boolean values still work, so nothing breaks. The descending parameter name is intentionally unchanged for backward compatibility. A follow-up PR is planned to extend the same support to query builder methods.
PHP 8.6 has not shipped yet, so this is forward preparation. A Symfony polyfill for SortDirection is already in progress for projects that want to adopt the enum before upgrading PHP.
@maherelgamil merged PR #59904, fixing a CI failure in EloquentModelDecimalCastingTest caused by an exception message that changed between brick/math versions.
Laravel's composer.json allows brick/math: ^0.14.2 || ^0.15 || ^0.16 || ^0.17, but the test was asserting the exact message from 0.14.x:
1// brick/math <= 0.142'The given value "foo" does not represent a valid number.'3 4// brick/math >= 0.155'Value "foo" does not represent a valid number.'
The fix switches to assertStringContainsString against the substring both versions share, so the test passes regardless of which brick/math version the resolver picks.
Four separate PRs tightened up annotations that were causing incorrect static analysis inference. None touch runtime behavior.
@mosabbirrakib merged PR #59892. In Illuminate\Contracts\Mail\Mailable, every fluent setter documented @return $this except cc(), which had @return self. The implementation already returned $this. The contract now matches, so chained calls like $mailable->cc(...)->bcc(...) on a typed contract reference resolve correctly in static analysis.
@mosabbirrakib also merged PR #59891. Both Batch::fresh() and Batch::add() were documented as @return self, but fresh() delegates to BatchRepository::find(), which is already typed @return Illuminate\Bus\Batch|null. Since add() returns $this->fresh(), it inherits the same nullability. Both annotations are now self|null. BatchFake keeps @return self because its override always returns $this.
@mosabbirrakib merged PR #59890. The abstract Lock::getCurrentOwner() and RedisLock::getCurrentOwner() were typed @return string, but the base class itself relies on null being a valid return:
1public function isLocked(): bool2{3 return $this->getCurrentOwner() !== null;4}
ArrayLock and DatabaseLock already documented string|null correctly. RedisLock returns $this->redis->get($this->name), which returns null when the key does not exist. Both incorrect annotations are now string|null.
@maherelgamil merged PR #59903. Schema\Builder::getForeignKeys() was the only get* method in the file with a bare @return array. Every sibling (getColumns, getIndexes, getTables, getViews, getTypes, getSchemas) already declared a detailed list<array{...}> shape. All four grammar implementations return the same structure, so the docblock now describes it precisely:
1/** 2 * @return list<array{ 3 * name: string|null, 4 * columns: list<string>, 5 * foreign_schema: string|null, 6 * foreign_table: string, 7 * foreign_columns: list<string>, 8 * on_update: string|null, 9 * on_delete: string|null,10 * }>11 */12public function getForeignKeys($table) {}
IDEs and static analysers working with schema introspection results will now see the full shape instead of array.
@taylorotwell pushed a small facade docblock update in the same batch, keeping generated facade stubs in sync with underlying method changes.
The PHPDoc wave across this batch reflects a broader push to make 13.x a stronger target for Psalm, PHPStan, and IDE tooling. If your codebase runs strict static analysis against Laravel internals, updating to the latest 13.x patch will remove several sources of incorrect inference without changing any runtime behavior.
If you enjoyed this article, please consider supporting our work for as low as $5 / month.
Sponsor
Written by
Writing and maintaining @LaravelMagazine. Host of "The Laravel Magazine Podcast". Pronouns: vi/vim.
Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.