Added the SEO package
This commit is contained in:
parent
cffa0f34a8
commit
30ee51d9d1
14 changed files with 267 additions and 14 deletions
|
|
@ -9,6 +9,9 @@ use App\Traits\Models\ActivityLog;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
|
||||
/**
|
||||
* @property string $seo_title SEO title.
|
||||
|
|
@ -31,10 +34,11 @@ use Illuminate\Support\Str;
|
|||
* @property-read \Carbon\Carbon $created_at Created date.
|
||||
* @property-read \Carbon\Carbon $updated_at Updated date.
|
||||
*/
|
||||
class News extends Model
|
||||
class News extends Model implements SeoInterface
|
||||
{
|
||||
use ActivityLog;
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -198,4 +202,22 @@ class News extends Model
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// * SEO TRAIT OVERLOAD
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \App\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans('models.classes.' . Str::singular($this->getTable())),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
$this->published ? \route('fo.' . $this->getTable() . '.show', $this) : ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ use App\Traits\Models\ActivityLog;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
|
||||
/**
|
||||
* @phpcs:disable Generic.Files.LineLength.TooLong
|
||||
|
|
@ -41,10 +44,11 @@ use Illuminate\Support\Str;
|
|||
* @property-read \App\Models\Range $range Range Belongs to relationship.
|
||||
* @phpcs:enable
|
||||
*/
|
||||
class Product extends Model
|
||||
class Product extends Model implements SeoInterface
|
||||
{
|
||||
use ActivityLog;
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -189,4 +193,22 @@ class Product extends Model
|
|||
{
|
||||
return $this->belongsToMany(Commitment::class);
|
||||
}
|
||||
|
||||
// * SEO TRAIT OVERLOAD
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \App\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans('models.classes.' . Str::singular($this->getTable())),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
$this->published ? \route('fo.' . $this->getTable() . '.show', $this) : ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ use App\Traits\Models\ActivityLog;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
|
||||
// phpcs:disable Generic.Files.LineLength.TooLong
|
||||
/**
|
||||
|
|
@ -36,10 +39,11 @@ use Illuminate\Support\Str;
|
|||
* @property-read \App\Models\Products $products Products Has Many relationship.
|
||||
*/
|
||||
// phpcs:enable
|
||||
class Range extends Model
|
||||
class Range extends Model implements SeoInterface
|
||||
{
|
||||
use ActivityLog;
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -170,4 +174,22 @@ class Range extends Model
|
|||
{
|
||||
return $this->hasMany(Product::class);
|
||||
}
|
||||
|
||||
// * SEO TRAIT OVERLOAD
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \App\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans('models.classes.' . Str::singular($this->getTable())),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
$this->published ?? false,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
$this->published ? \route('fo.' . $this->getTable() . '.show', $this) : ''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ use App\Traits\Models\ActivityLog;
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Uwil\Seo\Laravel\Interfaces\SeoInterface;
|
||||
use Uwil\Seo\Laravel\Objects\SeoItem;
|
||||
use Uwil\Seo\Laravel\Traits\SeoTrait;
|
||||
|
||||
/**
|
||||
* @property \App\Enums\StaticPageType $type Page type (StaticPageEnum).
|
||||
|
|
@ -19,10 +22,11 @@ use Illuminate\Support\Str;
|
|||
* @property-read \Illuminate\Support\Carbon $created_at Created date.
|
||||
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
|
||||
*/
|
||||
class StaticPage extends Model
|
||||
class StaticPage extends Model implements SeoInterface
|
||||
{
|
||||
use ActivityLog;
|
||||
use HasFactory;
|
||||
use SeoTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -83,4 +87,22 @@ class StaticPage extends Model
|
|||
ToolboxHelper::assertFieldIsUnique($table, 'title', $title, $id);
|
||||
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($title), $id);
|
||||
}
|
||||
|
||||
// * SEO TRAIT OVERLOAD
|
||||
/**
|
||||
* Transform to seoModel
|
||||
*
|
||||
* @return \App\Objects\SeoItem
|
||||
*/
|
||||
public function toSeoItem(): SeoItem
|
||||
{
|
||||
return new SeoItem(
|
||||
\trans('models.classes.' . Str::singular($this->getTable())),
|
||||
$this->seo_title,
|
||||
$this->seo_description,
|
||||
true,
|
||||
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,11 @@ class ViewServiceProvider extends ServiceProvider
|
|||
|
||||
if (!app()->runningInConsole()) {
|
||||
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
|
||||
// Early boot, request wont be filled as expected.
|
||||
if (collect(explode('/', \request()->getPathInfo()))->get(1) === 'bo') {
|
||||
// For the moment, we exclude the seo page because the new pagination system doesn't work in the package.
|
||||
if (
|
||||
collect(explode('/', \request()->getPathInfo()))->get(1) === 'bo' &&
|
||||
collect(explode('/', \request()->getPathInfo()))->last() !== 'seo'
|
||||
) {
|
||||
Paginator::defaultView('bo.modules.pagination');
|
||||
} else {
|
||||
Paginator::useBootstrapFive();
|
||||
|
|
@ -40,9 +43,9 @@ class ViewServiceProvider extends ServiceProvider
|
|||
// Get all the stamps that are pubished.
|
||||
$stamps = Cache::remember('randomStampsFooter', 360, function () {
|
||||
return DB::table('stamps')
|
||||
->select('picture', 'picture_alt', 'picture_title')
|
||||
->where('published', true)
|
||||
->get();
|
||||
->select('picture', 'picture_alt', 'picture_title')
|
||||
->where('published', true)
|
||||
->get();
|
||||
});
|
||||
/**
|
||||
* Share a collection of 1 or 2 random stamps for footer.
|
||||
|
|
@ -54,6 +57,6 @@ class ViewServiceProvider extends ServiceProvider
|
|||
'randomStampsFooter',
|
||||
$stamps->isNotEmpty() ? $stamps->random($stamps->count() >= 2 ? 2 : 1) : []
|
||||
);
|
||||
}//end if
|
||||
} //end if
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@
|
|||
"ldc/web-admin-secure-laravel": "^2.0",
|
||||
"mews/purifier": "^3.4",
|
||||
"sentry/sentry-laravel": "*",
|
||||
"uwil/k8s-laravel": "^1.2"
|
||||
"uwil/k8s-laravel": "^1.2",
|
||||
"uwil/seo-laravel": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
|
|
|
|||
49
composer.lock
generated
49
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5178515c35084bff77cb4cebec5574ab",
|
||||
"content-hash": "9e1490aea9d5c6f581ccaaafbba3e052",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
|
@ -8512,6 +8512,53 @@
|
|||
],
|
||||
"description": "Laravel requirements for k8s"
|
||||
},
|
||||
{
|
||||
"name": "uwil/seo-laravel",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://lab.s-web.fr/ldc-web/projets/seo-laravel.git",
|
||||
"reference": "518918847ada3a75dceda343ca074d7cdf8d0458"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://lab.s-web.fr/api/v4/projects/96/packages/composer/archives/uwil/seo-laravel.zip?sha=518918847ada3a75dceda343ca074d7cdf8d0458",
|
||||
"reference": "518918847ada3a75dceda343ca074d7cdf8d0458",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "~8|~9|~10",
|
||||
"laravel/framework": "~8|~9|~10",
|
||||
"php": "~7.4|~8"
|
||||
},
|
||||
"require-dev": {
|
||||
"slevomat/coding-standard": "^8.3",
|
||||
"squizlabs/php_codesniffer": "^3.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Uwil\\Seo\\Laravel\\SeoServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Uwil\\Seo\\Laravel\\": "src/"
|
||||
}
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Demangeat",
|
||||
"email": "nicolas.demangeat@ldc.fr"
|
||||
}
|
||||
],
|
||||
"description": "Find Seo title and seo description of a model"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v5.5.0",
|
||||
|
|
|
|||
12
config/seo.php
Normal file
12
config/seo.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'bo_route_prefix' => 'bo.',
|
||||
'blade' => 'bo.pages.seo.index',
|
||||
'middlewares' => [
|
||||
'web',
|
||||
'admin-secure',
|
||||
'auth:backend'
|
||||
],
|
||||
'guard' => 'backend'
|
||||
];
|
||||
|
|
@ -16,5 +16,6 @@ return [
|
|||
'convictionpage' => 'page conviction',
|
||||
'joinuspage' => 'page rejoignez-nous',
|
||||
'testimonial' => 'témoignage',
|
||||
'seo' => 'contenu SEO|contenus SEO'
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ return [
|
|||
'product_name' => 'nom du produit',
|
||||
'publication' => 'publication',
|
||||
'publish_at' => 'date de publication',
|
||||
'publish_at' => 'date de publication',
|
||||
'published' => 'état de publication',
|
||||
'send_data' => 'autorisation d\'enregistrer des données',
|
||||
'seo_description' => 'description SEO',
|
||||
'seo_title' => 'titre SEO',
|
||||
|
|
@ -284,6 +284,7 @@ return [
|
|||
'title_part1' => 'première partie du titre',
|
||||
'title_part2' => 'seconde partie du titre',
|
||||
'title_part3' => 'dernière partie du titre',
|
||||
'type' => 'type',
|
||||
'unpublish_at' => 'date de fin de publication',
|
||||
'unpublish_at' => 'date de fin de publication',
|
||||
'video_id' => 'ID de la vidéo',
|
||||
|
|
|
|||
|
|
@ -6,9 +6,16 @@
|
|||
{{ __('Accueil') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (Route::is('bo.seo.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.seo.index') }}"
|
||||
title="{{ __('Show the SEO informations') }}" role="button">
|
||||
{{ __('SEO') }}
|
||||
</a>
|
||||
</li>
|
||||
@can('viewAny', \App\Models\Commitment::class)
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.commitments.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.commitments.index') }}"
|
||||
<a class="nav-link @if (request()->routeIs('bo.commitments.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.commitments.index') }}"
|
||||
title="{{ __('crud.helpers.list_all', ['model' => Str::of(__('models.classes.commitment'))->plural()->ucfirst()]) }}">
|
||||
{{ Str::of(__('models.classes.commitment'))->plural()->ucfirst() }}
|
||||
</a>
|
||||
|
|
|
|||
50
resources/views/bo/pages/seo/index-list.blade.php
Normal file
50
resources/views/bo/pages/seo/index-list.blade.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<table class="table-hover table-fix-action m-0 table">
|
||||
@if (count($seoItemList) > 0)
|
||||
<thead>
|
||||
<tr class="border-start-0 border-end-0 border-top-0 border-dark border border-2 text-center">
|
||||
<th scope="col">{{ str(__('validation.custom.type'))->ucfirst() }}</th>
|
||||
<th scope="col">{{ str(__('validation.custom.seo_title'))->ucfirst() }}</th>
|
||||
<th scope="col">{{ str(__('validation.custom.seo_description'))->ucfirst() }}</th>
|
||||
<th scope="col">{{ str(__('validation.custom.published'))->ucfirst() }}</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($seoItemList as $seoItem)
|
||||
<tr class="border-bottom list-item text-center">
|
||||
<th scope="row">{{ str(trans_choice($seoItem->type, 1))->ucfirst() }}</th>
|
||||
<td>{{ $seoItem->seo_title }}</td>
|
||||
<td>{{ $seoItem->seo_description }}</td>
|
||||
<td class="text-center align-middle">
|
||||
@if ($seoItem->status)
|
||||
<i class="fs-6 text-success fa-solid fa-circle-check"></i>
|
||||
@else
|
||||
<i class="fs-6 text-danger fa-regular fa-circle-xmark"></i>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-end align-middle">
|
||||
<div class="btn-group">
|
||||
@if ($seoItem->status && $seoItem->fo_url !== '#' && $seoItem->fo_url !== '')
|
||||
<a class="btn btn-sm btn-warning" data-bs-toggle="tooltip" href="{{ $seoItem->fo_url }}"
|
||||
title="{{ __('Show') }}" target="_blank">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</a>
|
||||
@endif
|
||||
<a class="btn btn-sm btn-primary" data-bs-toggle="tooltip" href="{{ $seoItem->bo_url }}"
|
||||
title="{{ Str::ucfirst(__('crud.actions.update')) }}">
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@else
|
||||
<tr>
|
||||
<td class="border-0">{{ __('crud.other.no_model_found', ['model' => __('models.classes.range')]) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
<div class="mt-4">
|
||||
{{ $seoItemList->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
35
resources/views/bo/pages/seo/index.blade.php
Normal file
35
resources/views/bo/pages/seo/index.blade.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
@extends('bo.layout')
|
||||
|
||||
@section('title', Str::ucfirst(trans_choice('models.classes.seo', '*')))
|
||||
@section('description', trans_choice('crud.meta.description.index', 1, ['model' => trans_choice('models.classes.seo', '*')]))
|
||||
|
||||
@section('content')
|
||||
<div class="d-flex justify-content-between flex-md-nowrap align-items-center flex-wrap">
|
||||
@include('modules.breadcrumbs.breadcrumb-body')
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
<form class="float-start" action="{{ route('bo.seo.index') }}">
|
||||
<select class="form-select" id="type-filter" name="type">
|
||||
<option value="" @if (!request()->type) selected @endif>{{ __('Filtrer par type') }}</option>
|
||||
@foreach (\Uwil\Seo\Laravel\Http\Controllers\SeoController::slugifiedSeoModels() as $slugifiedSeoModel => $className)
|
||||
<option value="{{ $slugifiedSeoModel }}" @if (request()->type === $slugifiedSeoModel) selected @endif>
|
||||
{{ str($className)->ucfirst() }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@push('scripts')
|
||||
<script nonce="{{ $nonce }}">
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let typeFilter = document.getElementById('type-filter')
|
||||
typeFilter.addEventListener('change', () => typeFilter.parentElement.submit())
|
||||
})
|
||||
</script>
|
||||
@endpush
|
||||
<div class="table-responsive my-3">
|
||||
@include('bo.pages.seo.index-list')
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -233,3 +233,11 @@ Breadcrumbs::for('bo.testimonials.duplicate', function (Generator $trail) {
|
|||
$trail->parent('bo.testimonials.index');
|
||||
$trail->push(Str::ucfirst(trans('crud.actions.duplicate')));
|
||||
});
|
||||
|
||||
// * SEO
|
||||
Breadcrumbs::for('bo.seo.index', function (Generator $trail) {
|
||||
$trail->push(
|
||||
Str::of(trans_choice('models.classes.seo', '*'))->ucfirst(),
|
||||
route('bo.seo.index')
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue