@extends('layouts.admin') @section('title', 'Settings') @section('page-title', 'Settings') @section('content')
@if(session('success'))

{{ session('success') }}

@endif @if(session('error'))

{{ session('error') }}

@endif @if($categories && count($categories) > 0)
@endif
@csrf @method('POST') @if($category === 'updates') @php $installedVersion = null; $installedVersion = trim((string) config('mailpurse.version', '')); if ($installedVersion === '') { $installedVersion = $settings['updates']->get('app_version') ?? null; $installedVersion = is_string($installedVersion) ? trim((string) $installedVersion) : null; } $updateStatusPayload = is_array($updateStatus ?? null) ? $updateStatus : null; $updateAvailableFlag = is_array($updateStatusPayload) ? (bool) ($updateStatusPayload['update_available'] ?? false) : false; $updateStatusLatest = is_array($updateStatusPayload) && is_string($updateStatusPayload['latest_version'] ?? null) ? $updateStatusPayload['latest_version'] : null; $updateStatusCheckedAt = is_array($updateStatusPayload) && is_string($updateStatusPayload['checked_at'] ?? null) ? $updateStatusPayload['checked_at'] : null; $installTargetVersion = is_string($updateStatusLatest) && trim((string) $updateStatusLatest) !== '' ? (string) $updateStatusLatest : null; $latestVersion = null; $productData = null; if (is_array($updateProduct ?? null)) { $payload = $updateProduct['data'] ?? null; if (is_array($payload)) { if (is_array($payload['data'] ?? null)) { $productData = $payload['data']; } elseif (is_array($payload['product'] ?? null)) { $productData = $payload['product']; } else { $productData = $payload; } } } if (is_array($productData)) { $latestVersion = $productData['latest_version'] ?? ($productData['latestVersion'] ?? ($productData['latest'] ?? null)); if (!is_string($latestVersion) || trim((string) $latestVersion) === '') { $latestVersion = $productData['version'] ?? null; } } if (!is_string($latestVersion) || trim((string) $latestVersion) === '') { $changelogData = is_array($updateChangelogs ?? null) ? ($updateChangelogs['data'] ?? null) : null; if (is_array($changelogData)) { $versionMap = null; if (is_array($changelogData['releases'] ?? null)) { $versionMap = $changelogData['releases']; } elseif (is_array($changelogData['changelog'] ?? null)) { $versionMap = $changelogData['changelog']; } if (is_array($versionMap) && !empty($versionMap)) { $versions = array_keys($versionMap); usort($versions, function ($a, $b) { return version_compare((string) $b, (string) $a); }); $latestVersion = $versions[0] ?? null; } } } if (!$updateAvailableFlag && is_string($latestVersion) && is_string($installedVersion) && trim($latestVersion) !== '' && trim($installedVersion) !== '') { $updateAvailableFlag = version_compare((string) $latestVersion, (string) $installedVersion, '>'); } if (!is_string($installTargetVersion) || trim((string) $installTargetVersion) === '') { $installTargetVersion = is_string($latestVersion) && trim((string) $latestVersion) !== '' ? (string) $latestVersion : null; } @endphp
@if($updateAvailableFlag)

Update available

Installed: {{ is_string($installedVersion) && trim($installedVersion) !== '' ? $installedVersion : '—' }} | Latest: {{ is_string($updateStatusLatest) && trim($updateStatusLatest) !== '' ? $updateStatusLatest : (is_string($latestVersion) ? $latestVersion : '—') }}

@if(is_string($updateStatusCheckedAt) && trim($updateStatusCheckedAt) !== '')

Last checked: {{ $updateStatusCheckedAt }}

@endif
@endif

Updates

Check the latest available version from your update server and generate a download link.

Installed Version

{{ is_string($installedVersion) && trim($installedVersion) !== '' ? $installedVersion : '—' }}

Latest Version

{{ is_string($latestVersion) && trim((string) $latestVersion) !== '' ? $latestVersion : '—' }}

@if(is_array($updateProduct ?? null) && !($updateProduct['success'] ?? false))

{{ $updateProduct['message'] ?? 'Unable to fetch update info.' }}

@endif

Install Update

Install the latest version in the background. The site will go into maintenance mode during installation.

@admincan('admin.settings.edit') Install Update @endadmincan
@if(is_string($installTargetVersion ?? null) && trim((string) $installTargetVersion) !== '') @endif @php $installState = is_array($updateInstallState ?? null) ? $updateInstallState : null; $installInProgress = is_array($installState) ? (bool) ($installState['in_progress'] ?? false) : false; $installStatus = is_array($installState) && is_string($installState['status'] ?? null) ? $installState['status'] : null; $installMessage = is_array($installState) && is_string($installState['message'] ?? null) ? $installState['message'] : null; $installVersion = is_array($installState) && is_string($installState['version'] ?? null) ? $installState['version'] : null; @endphp @if($installInProgress || (is_string($installStatus) && trim((string) $installStatus) !== '') || (is_string($installMessage) && trim((string) $installMessage) !== ''))

Installer status

{{ is_string($installStatus) ? ucfirst($installStatus) : '—' }} @if(is_string($installVersion) && trim($installVersion) !== '') ({{ $installVersion }}) @endif

@if(is_string($installMessage) && trim($installMessage) !== '')

{{ $installMessage }}

@endif
@endif @if(is_string($updateLastFailureReason ?? null) && trim((string) $updateLastFailureReason) !== '')

Last update failed

@if(is_string($updateLastFailureVersion ?? null) && trim((string) $updateLastFailureVersion) !== '') Version: {{ $updateLastFailureVersion }} @else Version: — @endif @if(is_string($updateLastFailureAt ?? null) && trim((string) $updateLastFailureAt) !== '') | Date: {{ $updateLastFailureAt }} @endif

{{ $updateLastFailureReason }}

@endif @if(is_string($updateDownloadUrl ?? null) && trim((string) $updateDownloadUrl) !== '')
Open

This link may expire depending on your update server configuration.

@endif

Configuration

@php $licenseCheckPayload = is_array($updateLicenseCheck ?? null) ? ($updateLicenseCheck['data'] ?? null) : null; $licenseCheckTopStatus = is_array($licenseCheckPayload) && is_string($licenseCheckPayload['status'] ?? null) ? $licenseCheckPayload['status'] : null; $licenseCheckTopMessage = is_array($licenseCheckPayload) && is_string($licenseCheckPayload['message'] ?? null) ? $licenseCheckPayload['message'] : null; $licenseCheckRequestError = null; if (is_array($updateLicenseCheck ?? null) && !($updateLicenseCheck['success'] ?? false)) { $licenseCheckRequestError = is_string($updateLicenseCheck['message'] ?? null) ? $updateLicenseCheck['message'] : null; } $licenseObject = null; if (is_array($licenseCheckPayload) && is_array($licenseCheckPayload['data'] ?? null) && is_array($licenseCheckPayload['data']['license'] ?? null)) { $licenseObject = $licenseCheckPayload['data']['license']; } $savedLicense = null; try { $savedLicense = \App\Models\Setting::get('update_license_key'); } catch (\Throwable $e) { $savedLicense = null; } $maskedLicense = null; if (is_string($savedLicense) && trim($savedLicense) !== '') { $clean = trim((string) $savedLicense); if (preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $clean)) { $maskedLicense = substr($clean, 0, 8) . '-XXXX-XXXX-XXXX-' . substr($clean, -12); } else { $maskedLicense = substr($clean, 0, 8) . '…' . substr($clean, -6); } } @endphp

License

Status and support information from the license server.

@admincan('admin.settings.edit')
Deactivate
@endadmincan
@if(is_string($licenseCheckRequestError) && trim($licenseCheckRequestError) !== '')

{{ $licenseCheckRequestError }}

@endif

Status

{{ is_string($licenseObject['status'] ?? null) ? $licenseObject['status'] : ($licenseCheckTopStatus ?: '—') }}

@if(is_string($licenseCheckTopMessage) && trim($licenseCheckTopMessage) !== '')

{{ $licenseCheckTopMessage }}

@endif

License

{{ $maskedLicense ?: '—' }}

Support Expiry

{{ is_string($licenseObject['supported_until'] ?? null) ? $licenseObject['supported_until'] : '—' }}

License Type

{{ is_string($licenseObject['license_type'] ?? null) ? $licenseObject['license_type'] : '—' }}

Purchase Date

{{ is_string($licenseObject['purchase_date'] ?? null) ? $licenseObject['purchase_date'] : '—' }}

Envato Username

{{ is_string($licenseObject['envato_username'] ?? null) ? $licenseObject['envato_username'] : '—' }}

Domains

{{ is_numeric($licenseObject['active_domains'] ?? null) ? (int) $licenseObject['active_domains'] : '—' }} / {{ is_numeric($licenseObject['max_domains'] ?? null) ? (int) $licenseObject['max_domains'] : '—' }}

Normalized Domain

{{ is_string($licenseObject['normalized_domain'] ?? null) ? $licenseObject['normalized_domain'] : '—' }}

@if(is_array($licenseObject) && is_array($licenseObject['domains'] ?? null) && !empty($licenseObject['domains']))

Registered Domains

@foreach($licenseObject['domains'] as $d => $st) @endforeach
Domain Status
{{ is_string($d) ? $d : '' }} {{ is_string($st) ? $st : '' }}
@endif

Enter your purchase code / license key and click Activate.

@error('update_license_key')

{{ $message }}

@enderror
@elseif($category === 'changelogs') @php $items = []; $changelogMap = []; $releasesMap = []; $sortedVersions = []; if (is_array($updateChangelogs ?? null)) { $data = $updateChangelogs['data'] ?? null; if (is_array($data) && is_array($data['changelog'] ?? null)) { $changelogMap = $data['changelog']; $releasesMap = is_array($data['releases'] ?? null) ? $data['releases'] : []; } elseif (is_array($data) && is_array($data['changelogs'] ?? null)) { $items = $data['changelogs']; } elseif (is_array($data) && is_array($data['data'] ?? null)) { $items = $data['data']; } elseif (is_array($data)) { $items = $data; } } if (is_array($changelogMap) && !empty($changelogMap)) { $sortedVersions = array_keys($changelogMap); usort($sortedVersions, function ($a, $b) { return version_compare((string) $b, (string) $a); }); } @endphp

Changelogs

Release notes fetched from your update server.

@if(is_array($updateChangelogs ?? null) && !($updateChangelogs['success'] ?? false))
{{ $updateChangelogs['message'] ?? 'Unable to fetch changelogs.' }}
@endif @if(!empty($sortedVersions))
@foreach($sortedVersions as $version) @php $release = is_array($releasesMap[$version] ?? null) ? $releasesMap[$version] : []; $releaseDate = is_string($release['release_date'] ?? null) ? $release['release_date'] : null; $releaseChangelog = is_array($release['changelog'] ?? null) ? $release['changelog'] : null; $entry = is_array($releaseChangelog) ? $releaseChangelog : (is_array($changelogMap[$version] ?? null) ? $changelogMap[$version] : []); @endphp

{{ $version }}

{{ $releaseDate ?: '' }}

@foreach($entry as $type => $messages) @php $title = is_string($type) ? ucfirst(str_replace('_', ' ', $type)) : 'Changes'; $lines = []; $messageList = []; if (is_string($messages) && trim($messages) !== '') { $messageList = [$messages]; } elseif (is_array($messages)) { $messageList = $messages; } if (!empty($messageList)) { foreach ($messageList as $msg) { if (!is_string($msg)) { continue; } $parts = array_map('trim', explode(',', $msg)); foreach ($parts as $part) { if ($part !== '') { $lines[] = $part; } } } } @endphp @if(!empty($lines))

{{ $title }}

    @foreach($lines as $line)
  • {{ $line }}
  • @endforeach
@endif @endforeach
@endforeach
@elseif(!empty($items))
@foreach($items as $item) @php $version = is_array($item) && is_string($item['version'] ?? null) ? $item['version'] : null; $date = is_array($item) && is_string($item['date'] ?? null) ? $item['date'] : null; $content = is_array($item) && is_string($item['content'] ?? null) ? $item['content'] : null; @endphp

{{ $version ?: 'Release' }}

{{ $date ?: '' }}

@if($content)
{!! $content !!}
@endif
@endforeach
@else

No changelog entries available.

@endif
@elseif($category === 'cron') @php $settingsByKey = $settings->get($category, collect())->keyBy('key'); $cronEnabled = (bool) ($settingsByKey['cron_web_enabled']->value ?? false); $cronToken = is_string($settingsByKey['cron_web_token']->value ?? null) ? (string) $settingsByKey['cron_web_token']->value : ''; $cronLastRunAt = is_string($settingsByKey['cron_last_run_at']->value ?? null) ? (string) $settingsByKey['cron_last_run_at']->value : ''; $cronUrl = route('cron.run', ['token' => $cronToken]); $cronWgetCommand = 'wget -q -O - "' . $cronUrl . '" > /dev/null 2>&1'; $cronCurlCommand = 'curl -fsS "' . $cronUrl . '" > /dev/null 2>&1'; $cronRunOutput = session('cron_run_output'); @endphp

Cron / Scheduler

Use this for cPanel cron jobs (or any external scheduler) to trigger Laravel's scheduler.

Web Cron

When enabled, calls to the Web Cron URL will run schedule:run.

@error('cron_web_enabled')

{{ $message }}

@enderror

Add this URL in cPanel Cron Jobs (every minute). Keep the token secret.

@admincan('admin.settings.edit') Regenerate Token Run Now @endadmincan

Last run

{{ $cronLastRunAt !== '' ? $cronLastRunAt : '—' }}

Status

{{ $cronEnabled ? 'Enabled' : 'Disabled' }}

@if(is_string($cronRunOutput) && trim((string) $cronRunOutput) !== '')

Last run output

{{ $cronRunOutput }}
@endif
@elseif($category === 'storage') @php $settingsByKey = $settings->get($category, collect())->keyBy('key'); $getVal = function (string $key, $default = null) { try { return \App\Models\Setting::get($key, $default); } catch (\Throwable $e) { return $default; } }; $s3Configured = is_string($getVal('s3_key')) && trim((string) $getVal('s3_key')) !== '' && is_string($getVal('s3_secret')) && trim((string) $getVal('s3_secret')) !== '' && is_string($getVal('s3_region')) && trim((string) $getVal('s3_region')) !== '' && is_string($getVal('s3_bucket')) && trim((string) $getVal('s3_bucket')) !== ''; $wasabiConfigured = is_string($getVal('wasabi_key')) && trim((string) $getVal('wasabi_key')) !== '' && is_string($getVal('wasabi_secret')) && trim((string) $getVal('wasabi_secret')) !== '' && is_string($getVal('wasabi_region')) && trim((string) $getVal('wasabi_region')) !== '' && is_string($getVal('wasabi_bucket')) && trim((string) $getVal('wasabi_bucket')) !== '' && is_string($getVal('wasabi_endpoint')) && trim((string) $getVal('wasabi_endpoint')) !== ''; $gcsConfigured = is_string($getVal('gcs_project_id')) && trim((string) $getVal('gcs_project_id')) !== '' && is_string($getVal('gcs_bucket')) && trim((string) $getVal('gcs_bucket')) !== '' && is_string($getVal('gcs_key_file')) && trim((string) $getVal('gcs_key_file')) !== ''; @endphp

Providers

Enable/disable providers. The app will use your default storage from General settings, and fall back to Local if the provider is disabled or not configured.

Provider Active Configured
Local @error('storage_local_enabled')

{{ $message }}

@enderror
Yes
Amazon S3 @error('storage_s3_enabled')

{{ $message }}

@enderror
{{ $s3Configured ? 'Yes' : 'No' }}
Wasabi @error('storage_wasabi_enabled')

{{ $message }}

@enderror
{{ $wasabiConfigured ? 'Yes' : 'No' }}
Google Cloud Storage @error('storage_gcs_enabled')

{{ $message }}

@enderror
{{ $gcsConfigured ? 'Yes' : 'No' }}

Common

Root folder/prefix to store public assets under (optional).

@php $storagePublicRootOptions = [ '' => 'None', 'public' => 'public', 'uploads' => 'uploads', 'assets' => 'assets', 'media' => 'media', ]; $storagePublicRootValue = $getVal('storage_public_root', 'public'); $storagePublicRootValue = is_string($storagePublicRootValue) ? trim($storagePublicRootValue) : ''; $storagePublicRootIsCustom = !array_key_exists($storagePublicRootValue, $storagePublicRootOptions); @endphp
@error('storage_public_root')

{{ $message }}

@enderror

Amazon S3 Settings

@error('s3_key')

{{ $message }}

@enderror
@error('s3_secret')

{{ $message }}

@enderror
@error('s3_region')

{{ $message }}

@enderror
@error('s3_bucket')

{{ $message }}

@enderror
@error('s3_endpoint')

{{ $message }}

@enderror
@error('s3_url')

{{ $message }}

@enderror

Wasabi Settings

@error('wasabi_key')

{{ $message }}

@enderror
@error('wasabi_secret')

{{ $message }}

@enderror
@error('wasabi_region')

{{ $message }}

@enderror
@error('wasabi_bucket')

{{ $message }}

@enderror
@error('wasabi_endpoint')

{{ $message }}

@enderror
@error('wasabi_url')

{{ $message }}

@enderror

Google Cloud Storage Settings

@error('gcs_project_id')

{{ $message }}

@enderror
@error('gcs_bucket')

{{ $message }}

@enderror

Absolute path to service account JSON file on the server.

@error('gcs_key_file')

{{ $message }}

@enderror
@error('gcs_path_prefix')

{{ $message }}

@enderror
@error('gcs_url')

{{ $message }}

@enderror
@elseif($category === 'ai' && $settings->has($category) && $settings[$category]->count() > 0) @php $aiSettings = $settings[$category]; $openaiSettings = $aiSettings->filter(fn ($s) => \Illuminate\Support\Str::startsWith((string) $s->key, 'openai_')); $geminiSettings = $aiSettings->filter(fn ($s) => \Illuminate\Support\Str::startsWith((string) $s->key, 'gemini_')); $claudeSettings = $aiSettings->filter(fn ($s) => \Illuminate\Support\Str::startsWith((string) $s->key, 'claude_')); $otherAiSettings = $aiSettings->reject(function ($s) { return \Illuminate\Support\Str::startsWith((string) $s->key, 'openai_') || \Illuminate\Support\Str::startsWith((string) $s->key, 'gemini_') || \Illuminate\Support\Str::startsWith((string) $s->key, 'claude_'); }); $groups = [ ['title' => 'OpenAI / GPT', 'items' => $openaiSettings], ['title' => 'Gemini', 'items' => $geminiSettings], ['title' => 'Claude', 'items' => $claudeSettings], ]; @endphp
@foreach($groups as $group) @php $items = $group['items'] ?? collect(); @endphp @if($items->count() > 0)
{{ $group['title'] ?? '' }}
@foreach($items as $setting) @include('admin.settings._setting_field', ['setting' => $setting]) @endforeach
@endif @endforeach @if($otherAiSettings->count() > 0)
{{ __('Other') }}
@foreach($otherAiSettings as $setting) @include('admin.settings._setting_field', ['setting' => $setting]) @endforeach
@endif
@elseif($category === 'navigation' && $settings->has($category) && $settings[$category]->count() > 0) @php $navigationSettings = $settings[$category] ->reject(fn ($s) => in_array((string) ($s->key ?? ''), ['nav_show_home_dropdown', 'nav_show_home_1', 'nav_show_home_2', 'nav_show_home_3', 'nav_show_home_4'], true)); @endphp
@foreach($navigationSettings as $setting) @include('admin.settings._setting_field', ['setting' => $setting]) @endforeach
@elseif($settings->has($category) && $settings[$category]->count() > 0)
@foreach($settings[$category] as $setting) @include('admin.settings._setting_field', ['setting' => $setting]) @endforeach
@else

No settings found for this category.

Settings will appear here once they are created.

@endif @if($settings->has($category) && $settings[$category]->count() > 0)
@admincan('admin.settings.edit') Save Settings @endadmincan
@endif
@endsection