├── resources └── lang │ ├── en │ └── fields.php │ └── tr │ └── fields.php ├── src ├── Facades │ └── FilamentPageManager.php ├── Contracts │ └── IPageTemplate.php ├── Resources │ ├── PageResource │ │ └── Pages │ │ │ ├── ListPages.php │ │ │ ├── CreatePage.php │ │ │ └── EditPage.php │ └── PageResource.php ├── Templates │ └── PageTemplate.php ├── FilamentPageManagerServiceProvider.php ├── Models │ └── Page.php ├── Console │ └── Commands │ │ └── CreatePageTemplateCommand.php └── FilamentPageManager.php ├── config └── filament-page-manager.php ├── stubs └── PageTemplate.stub ├── database └── migrations │ └── create_pages_table.php.stub ├── LICENSE.md ├── CHANGELOG.md ├── composer.json └── README.md /resources/lang/en/fields.php: -------------------------------------------------------------------------------- 1 | 'Name', 5 | 'slug' => 'Slug', 6 | 'template' => 'Template', 7 | 'creation_date' => 'Creation date', 8 | 'updated_date' => 'Updated date', 9 | ]; 10 | -------------------------------------------------------------------------------- /resources/lang/tr/fields.php: -------------------------------------------------------------------------------- 1 | 'İsim', 5 | 'slug' => 'Slug', 6 | 'template' => 'Şablon', 7 | 'creation_date' => 'Oluşturulma tarihi', 8 | 'updated_date' => 'Güncellenme tarihi', 9 | ]; 10 | -------------------------------------------------------------------------------- /src/Facades/FilamentPageManager.php: -------------------------------------------------------------------------------- 1 | \FurkanGM\FilamentPageManager\Models\Page::class, 5 | 6 | 'resource' => [ 7 | 'class' => \FurkanGM\FilamentPageManager\Resources\PageResource::class, 8 | 'label' => null, 9 | 'navigation_group' => null, 10 | 'navigation_icon' => null, 11 | 'navigation_label' => null, 12 | 'navigation_sort' => null, 13 | 'plural_label' => null, 14 | ], 15 | 16 | 'templates' => [], 17 | ]; 18 | -------------------------------------------------------------------------------- /src/Contracts/IPageTemplate.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 12 | $table->string('name', 255); 13 | $table->string('slug', 255); 14 | $table->string('template', 255); 15 | $table->json('data')->nullable(); 16 | $table->timestamps(); 17 | }); 18 | } 19 | 20 | public function down() 21 | { 22 | Schema::dropIfExists('pages'); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/Resources/PageResource/Pages/CreatePage.php: -------------------------------------------------------------------------------- 1 | except(PageResource::DEFAULT_FIELDS)->toArray(); 18 | $defaultFields = $data->only(PageResource::DEFAULT_FIELDS)->toArray(); 19 | 20 | return $this->getModel()::create(array_merge($defaultFields, ['data' => $additionalFields])); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) FurkanGM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Templates/PageTemplate.php: -------------------------------------------------------------------------------- 1 | isSlugHidden = $hidden; 44 | } 45 | 46 | public function isSlugHidden(): bool 47 | { 48 | return $this->isSlugHidden; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/FilamentPageManagerServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->bind(FilamentPageManager::class, fn ($app) => new FilamentPageManager()); 15 | } 16 | 17 | public function configurePackage(Package $package): void 18 | { 19 | $package 20 | ->name('filament-page-manager') 21 | ->hasConfigFile() 22 | ->hasTranslations() 23 | ->hasMigration('create_pages_table') 24 | ->hasCommand(CreatePageTemplateCommand::class); 25 | } 26 | 27 | protected function getResources(): array 28 | { 29 | return [ 30 | FilamentPageManagerFacade::getResource(), 31 | ]; 32 | } 33 | 34 | public function packageBooted(): void 35 | { 36 | parent::packageBooted(); 37 | 38 | FilamentPageManagerFacade::setPageTemplates(config('filament-page-manager.templates')); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `filament-page-manager` will be documented in this file. 4 | 5 | ## v1.0.1 - 2023-03-26 6 | 7 | ### What's Changed 8 | 9 | - Bump aglipanci/laravel-pint-action from 1.0.0 to 2.1.0 by @dependabot in https://github.com/FurkanGM/filament-page-manager/pull/2 10 | - Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/FurkanGM/filament-page-manager/pull/3 11 | - Bump aglipanci/laravel-pint-action from 2.1.0 to 2.2.0 by @dependabot in https://github.com/FurkanGM/filament-page-manager/pull/4 12 | - feat: laravel 10 support by @FurkanGM in https://github.com/FurkanGM/filament-page-manager/pull/6 13 | 14 | ### New Contributors 15 | 16 | - @dependabot made their first contribution in https://github.com/FurkanGM/filament-page-manager/pull/2 17 | 18 | **Full Changelog**: https://github.com/FurkanGM/filament-page-manager/compare/v1.0.0...v1.0.1 19 | 20 | ## v1.0.0 - 2022-12-23 21 | 22 | ### What's Changed 23 | 24 | - First release by @FurkanGM in https://github.com/FurkanGM/filament-page-manager/pull/1 25 | 26 | ### New Contributors 27 | 28 | - @FurkanGM made their first contribution in https://github.com/FurkanGM/filament-page-manager/pull/1 29 | 30 | **Full Changelog**: https://github.com/FurkanGM/filament-page-manager/commits/v1.0.0 31 | 32 | ## 1.0.0 - 202X-XX-XX 33 | 34 | - initial release 35 | -------------------------------------------------------------------------------- /src/Resources/PageResource/Pages/EditPage.php: -------------------------------------------------------------------------------- 1 | callHook('beforeFill'); 24 | 25 | $data = collect($this->getRecord()->attributesToArray()) 26 | ->mapWithKeys(fn ($value, $key) => $key === 'data' ? [...$value] : [$key => $value]) 27 | ->toArray(); 28 | 29 | $data = $this->mutateFormDataBeforeFill($data); 30 | 31 | $this->form->fill($data); 32 | 33 | $this->callHook('afterFill'); 34 | } 35 | 36 | protected function handleRecordUpdate(Model $record, array $data): Model 37 | { 38 | $data = collect($data); 39 | 40 | $additionalFields = $data->except(PageResource::DEFAULT_FIELDS)->toArray(); 41 | $defaultFields = $data->only(PageResource::DEFAULT_FIELDS)->toArray(); 42 | 43 | $record->update(array_merge($defaultFields, ['data' => $additionalFields])); 44 | 45 | return $record; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Models/Page.php: -------------------------------------------------------------------------------- 1 | 'json', 17 | ]; 18 | 19 | public function resolveRouteBindingQuery($query, $value, $field = null): Builder|Relation 20 | { 21 | $field = $field ?? $this->getRouteKeyName(); 22 | 23 | if ($field !== $this->getRouteKeyName()) { 24 | return parent::resolveRouteBindingQuery($query, $value, $field); 25 | } 26 | 27 | return $query->where($field, $value); 28 | } 29 | 30 | public function getRouteKeyName(): string 31 | { 32 | return 'slug'; 33 | } 34 | 35 | public function getTemplateAttribute($template): string|bool|null 36 | { 37 | return mb_strtolower($template); 38 | } 39 | 40 | public function getSlugAttribute($slug): string 41 | { 42 | $pageTemplate = $this->getTemplate(); 43 | 44 | return $pageTemplate instanceof PageTemplate 45 | ? ($pageTemplate->isSlugHidden() ? '' : $slug) 46 | : $slug; 47 | } 48 | 49 | public function getTemplate(): ?PageTemplate 50 | { 51 | return FilamentPageManager::getPageTemplate($this->template); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Console/Commands/CreatePageTemplateCommand.php: -------------------------------------------------------------------------------- 1 | argument('name') ?? $this->ask('What is page template name?'); 20 | 21 | $name = str($name) 22 | ->studly() 23 | ->beforeLast('Template'); 24 | 25 | $className = $this->qualifyClass($name); 26 | 27 | $className .= 'Template'; 28 | 29 | if ($this->isReservedName($className)) { 30 | $this->error('The name "'.$className.'" is reserved by PHP.'); 31 | 32 | return false; 33 | } 34 | 35 | $path = $this->getPath($className); 36 | 37 | if ($this->files->exists($path)) { 38 | $this->error(basename($className).' already exists!'); 39 | 40 | return false; 41 | } 42 | 43 | $this->makeDirectory($path); 44 | 45 | $class = $this->buildClass($className); 46 | 47 | $this->files->put($path, $this->sortImports(str_replace('{{ name }}', $name->lower(), $class))); 48 | 49 | $viewPath = resource_path("views/templates/{$name->lower()}.blade.php"); 50 | 51 | if (! file_exists($viewPath)) { 52 | $this->files->put($viewPath, "// {$name} page template"); 53 | } 54 | 55 | $this->info($this->type.' created successfully.'); 56 | 57 | return true; 58 | } 59 | 60 | protected function getDefaultNamespace($rootNamespace): string 61 | { 62 | return $rootNamespace.'\\Support\\PageTemplates'; 63 | } 64 | 65 | protected function getStub(): string 66 | { 67 | return __DIR__.'/../../../stubs/PageTemplate.stub'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/FilamentPageManager.php: -------------------------------------------------------------------------------- 1 | */ 12 | public string $model; 13 | 14 | /** @var class-string */ 15 | public string $resource; 16 | 17 | public array $pageTemplates = []; 18 | 19 | public function __construct() 20 | { 21 | $this->setModel(config('filament-page-manager.model', Page::class)); 22 | $this->setResource(config('filament-page-manager.resource.class', PageResource::class)); 23 | } 24 | 25 | public function setModel(string $model): void 26 | { 27 | $this->model = $model; 28 | } 29 | 30 | /** 31 | * @return class-string 32 | */ 33 | public function getModel() 34 | { 35 | return $this->model; 36 | } 37 | 38 | public function setResource(string $resource): void 39 | { 40 | $this->resource = $resource; 41 | } 42 | 43 | /** 44 | * @return class-string 45 | */ 46 | public function getResource() 47 | { 48 | return $this->resource; 49 | } 50 | 51 | public function getPageTemplate(string $name): ?PageTemplate 52 | { 53 | return collect($this->getPageTemplates())->get($name); 54 | } 55 | 56 | public function getPageTemplates(): array 57 | { 58 | return collect($this->pageTemplates) 59 | ->filter(fn (string $pageTemplate) => class_exists($pageTemplate)) 60 | ->mapWithKeys(fn (string $pageTemplate) => [$pageTemplate => new $pageTemplate()]) 61 | ->mapWithKeys(fn (PageTemplate $page) => [$page->getName() => $page]) 62 | ->toArray(); 63 | } 64 | 65 | /** 66 | * @param PageTemplate[] $pageTemplates 67 | */ 68 | public function setPageTemplates(array $pageTemplates): void 69 | { 70 | $this->pageTemplates = $pageTemplates; 71 | } 72 | 73 | public function getPageTemplateOptions(): array 74 | { 75 | return collect($this->getPageTemplates()) 76 | ->mapWithKeys(fn (PageTemplate $page) => [$page->getName() => $page->getLabel()]) 77 | ->toArray(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "furkangm/filament-page-manager", 3 | "description": "Filament page manager", 4 | "keywords": [ 5 | "FurkanGM", 6 | "laravel", 7 | "filament-page-manager" 8 | ], 9 | "homepage": "https://github.com/furkangm/filament-page-manager", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Furkan Gezek", 14 | "email": "furkangezek2014@gmail.com", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.0", 20 | "filament/filament": "^2.0", 21 | "spatie/laravel-package-tools": "^1.13.5", 22 | "illuminate/contracts": "^9.0|^10.0" 23 | }, 24 | "require-dev": { 25 | "laravel/pint": "^1.0", 26 | "nunomaduro/collision": "^6.0", 27 | "nunomaduro/larastan": "^2.0.1", 28 | "orchestra/testbench": "^7.0|^8.0", 29 | "pestphp/pest": "^1.21", 30 | "pestphp/pest-plugin-laravel": "^1.1", 31 | "pestphp/pest-plugin-livewire": "^1.0", 32 | "pestphp/pest-plugin-parallel": "^0.3", 33 | "phpstan/extension-installer": "^1.1", 34 | "phpstan/phpstan-deprecation-rules": "^1.0", 35 | "phpstan/phpstan-phpunit": "^1.0", 36 | "phpunit/phpunit": "^9.5", 37 | "spatie/laravel-ray": "^1.26" 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "FurkanGM\\FilamentPageManager\\": "src", 42 | "FurkanGM\\FilamentPageManager\\Database\\Factories\\": "database/factories" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "FurkanGM\\FilamentPageManager\\Tests\\": "tests" 48 | } 49 | }, 50 | "scripts": { 51 | "pint": "vendor/bin/pint", 52 | "test:pest": "vendor/bin/pest --parallel", 53 | "test:phpstan": "vendor/bin/phpstan analyse", 54 | "test": [ 55 | "@test:pest", 56 | "@test:phpstan" 57 | ] 58 | }, 59 | "config": { 60 | "sort-packages": true, 61 | "allow-plugins": { 62 | "composer/package-versions-deprecated": true, 63 | "pestphp/pest-plugin": true, 64 | "phpstan/extension-installer": true 65 | } 66 | }, 67 | "extra": { 68 | "laravel": { 69 | "providers": [ 70 | "FurkanGM\\FilamentPageManager\\FilamentPageManagerServiceProvider" 71 | ], 72 | "aliases": { 73 | "FilamentPageManager": "FurkanGM\\FilamentPageManager\\Facades\\FilamentPageManager" 74 | } 75 | } 76 | }, 77 | "minimum-stability": "dev", 78 | "prefer-stable": true 79 | } 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filament page manager 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/furkangm/filament-page-manager.svg?style=flat-square)](https://packagist.org/packages/furkangm/filament-page-manager) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/furkangm/filament-page-manager/run-tests?label=tests)](https://github.com/furkangm/filament-page-manager/actions?query=workflow%3Arun-tests+branch%3Amain) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/furkangm/filament-page-manager/Check%20&%20fix%20styling?label=code%20style)](https://github.com/furkangm/filament-page-manager/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/furkangm/filament-page-manager.svg?style=flat-square)](https://packagist.org/packages/furkangm/filament-page-manager) 7 | 8 | 9 | ## Installation 10 | 11 | You can install the package via composer: 12 | 13 | ```bash 14 | composer require furkangm/filament-page-manager 15 | ``` 16 | 17 | You can publish and run the migrations with: 18 | 19 | ```bash 20 | php artisan vendor:publish --tag="filament-page-manager-migrations" 21 | php artisan migrate 22 | ``` 23 | 24 | You can publish the config file with: 25 | 26 | ```bash 27 | php artisan vendor:publish --tag="filament-page-manager-config" 28 | ``` 29 | 30 | ## Usage 31 | 32 | First create page template with make command 33 | 34 | ```shell 35 | php artisan make:page-template {name?} 36 | ``` 37 | 38 | Also you can create manually page template with extend `\FurkanGM\FilamentPageManager\Templates\PageTemplate` class 39 | 40 | ```php 41 | class ExampleTemplate extends \FurkanGM\FilamentPageManager\Templates\PageTemplate 42 | { 43 | // .... 44 | } 45 | ``` 46 | 47 | After creating page, you should register page template in config file. 48 | 49 | ```php 50 | 'templates' => [ 51 | // ... 52 | CreatedPageTemplate::class 53 | ] 54 | ``` 55 | 56 | If you want register templates without config file, you can use `FilamentPageManager` facade. 57 | 58 | ```php 59 | app(\FurkanGM\FilamentPageManager\FilamentPageManager::class)->setPageTemplates([ 60 | // templates... 61 | ]); 62 | ``` 63 | 64 | ## Customization 65 | 66 | You can extend `Page` model and `PageResource` resource. 67 | 68 | ## Changelog 69 | 70 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 71 | 72 | ## Contributing 73 | 74 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 75 | 76 | ## Security Vulnerabilities 77 | 78 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 79 | 80 | ## Credits 81 | 82 | - [Furkan Gezek](https://github.com/FurkanGM) 83 | - [All Contributors](../../contributors) 84 | 85 | ## License 86 | 87 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 88 | -------------------------------------------------------------------------------- /src/Resources/PageResource.php: -------------------------------------------------------------------------------- 1 | columns(3) 26 | ->schema([ 27 | Forms\Components\Grid::make() 28 | ->columnSpan(2) 29 | ->schema(function ($livewire, $get, $record) { 30 | $additionalMainFields = []; 31 | $additionalOutsideFields = []; 32 | 33 | if ($livewire instanceof (Pages\EditPage::class) || filled($get('template'))) { 34 | $additionalMainFields = $record->getTemplate()->mainFields() ?? FilamentPageManager::getPageTemplate($get('template'))->mainFields(); 35 | $additionalOutsideFields = $record->getTemplate()->outsideFields() ?? FilamentPageManager::getPageTemplate($get('template'))->outsideFields(); 36 | } 37 | 38 | return array_merge([ 39 | Forms\Components\Card::make() 40 | ->schema(array_merge([ 41 | Forms\Components\TextInput::make('name') 42 | ->label(__('filament-page-manager::fields.name')) 43 | ->required() 44 | ->reactive() 45 | ->afterStateUpdated(fn (Closure $set, $state) => $set('slug', Str::slug($state))), 46 | Forms\Components\TextInput::make('slug') 47 | ->label(__('filament-page-manager::fields.slug')) 48 | ->required(fn ($livewire, ?Page $record) => ! $livewire instanceof Pages\EditPage || ! $record?->getTemplate()->isSlugHidden()) 49 | ->unique('pages', 'slug', fn ($record) => $record), 50 | Forms\Components\Select::make('template') 51 | ->label(__('filament-page-manager::fields.template')) 52 | ->required() 53 | ->reactive() 54 | ->options(FilamentPageManager::getPageTemplateOptions()) 55 | ->disabled(fn ($livewire) => $livewire instanceof Pages\EditPage), 56 | ], $additionalMainFields)), 57 | ], $additionalOutsideFields); 58 | }), 59 | Forms\Components\Grid::make() 60 | ->columnSpan(1) 61 | ->schema(function ($livewire, $get, $record) { 62 | $additionalFields = []; 63 | 64 | if ($livewire instanceof (Pages\EditPage::class) || filled($get('template'))) { 65 | $additionalFields = $record?->getTemplate()->sidebarFields() ?? FilamentPageManager::getPageTemplate($get('template'))->sidebarFields(); 66 | } 67 | 68 | return array_merge([ 69 | Forms\Components\Card::make() 70 | ->columnSpan(2) 71 | ->schema([ 72 | Forms\Components\Placeholder::make('created_at') 73 | ->label(__('filament-page-manager::fields.creation_date')) 74 | ->content(fn (?Page $record): string => $record?->created_at->diffForHumans() ?? '-'), /* @phpstan-ignore-line */ 75 | Forms\Components\Placeholder::make('updated_at') 76 | ->label(__('filament-page-manager::fields.updated_date')) 77 | ->content(fn (?Page $record): string => $record?->updated_at->diffForHumans() ?? '-'), /* @phpstan-ignore-line */ 78 | ]), 79 | ], $additionalFields); 80 | }), 81 | ]); 82 | } 83 | 84 | public static function table(Table $table): Table 85 | { 86 | return $table 87 | ->columns([ 88 | Tables\Columns\TextColumn::make('name')->label(__('filament-page-manager::fields.name')), 89 | Tables\Columns\TextColumn::make('slug')->label(__('filament-page-manager::fields.slug')), 90 | Tables\Columns\TextColumn::make('template')->label(__('filament-page-manager::fields.template'))->enum(FilamentPageManager::getPageTemplateOptions()), 91 | ]) 92 | ->actions([ 93 | Tables\Actions\EditAction::make(), 94 | ]) 95 | ->bulkActions([ 96 | Tables\Actions\DeleteBulkAction::make(), 97 | ]); 98 | } 99 | 100 | public static function getPages(): array 101 | { 102 | return [ 103 | 'index' => Pages\ListPages::route('/'), 104 | 'create' => Pages\CreatePage::route('/create'), 105 | 'edit' => Pages\EditPage::route('/{record:id}/edit'), 106 | ]; 107 | } 108 | 109 | public static function getModel(): string 110 | { 111 | return FilamentPageManager::getModel(); 112 | } 113 | 114 | public static function getModelLabel(): string 115 | { 116 | return config('filament-page-manager.resource.label') ?? parent::getModelLabel(); 117 | } 118 | 119 | public static function getPluralModelLabel(): string 120 | { 121 | return config('filament-page-manager.resource.plural_label') ?? parent::getPluralModelLabel(); 122 | } 123 | 124 | protected static function getNavigationLabel(): string 125 | { 126 | return config('filament-page-manager.resource.navigation_label') ?? parent::getNavigationLabel(); 127 | } 128 | 129 | protected static function getNavigationGroup(): ?string 130 | { 131 | return config('filament-page-manager.resource.navigation_group') ?? parent::getNavigationGroup(); 132 | } 133 | 134 | protected static function getNavigationIcon(): string 135 | { 136 | return config('filament-page-manager.resource.navigation_icon') ?? parent::getNavigationIcon(); 137 | } 138 | 139 | protected static function getNavigationSort(): ?int 140 | { 141 | return config('filament-page-manager.resource.navigation_sort_order') ?? parent::getNavigationSort(); 142 | } 143 | } 144 | --------------------------------------------------------------------------------