Added the SEO package

This commit is contained in:
Noah Lancien 2024-01-08 10:54:20 +01:00
parent cffa0f34a8
commit 30ee51d9d1
14 changed files with 267 additions and 14 deletions

View file

@ -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) : ''
);
}
}

View file

@ -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) : ''
);
}
}

View file

@ -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) : ''
);
}
}

View file

@ -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),
''
);
}
}

View file

@ -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
}
}

View file

@ -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
View file

@ -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
View file

@ -0,0 +1,12 @@
<?php
return [
'bo_route_prefix' => 'bo.',
'blade' => 'bo.pages.seo.index',
'middlewares' => [
'web',
'admin-secure',
'auth:backend'
],
'guard' => 'backend'
];

View file

@ -16,5 +16,6 @@ return [
'convictionpage' => 'page conviction',
'joinuspage' => 'page rejoignez-nous',
'testimonial' => 'témoignage',
'seo' => 'contenu SEO|contenus SEO'
]
];

View file

@ -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',

View file

@ -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>

View 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>

View 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

View file

@ -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')
);
});