Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Noah Lancien
0e194311bb Added SEO package 2024-01-05 14:05:27 +00:00
13 changed files with 237 additions and 6 deletions

View file

@ -8,6 +8,9 @@ use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str; 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 Utilisé pour la balise title de la page. * @property string $seo_title Utilisé pour la balise title de la page.
@ -25,10 +28,11 @@ use Illuminate\Support\Str;
* @property-read \Carbon\Carbon $created_at Created date. * @property-read \Carbon\Carbon $created_at Created date.
* @property-read \Carbon\Carbon $updated_at Updated date. * @property-read \Carbon\Carbon $updated_at Updated date.
*/ */
class News extends Model class News extends Model implements SeoInterface
{ {
use ActivityLog; use ActivityLog;
use HasFactory; use HasFactory;
use SeoTrait;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@ -163,4 +167,22 @@ class News extends Model
} }
return false; return false;
} }
// * SEO TRAIT OVERLOAD
/**
* Transform to seoModel
*
* @return \App\Objects\SeoItem
*/
public function toSeoItem(): SeoItem
{
return new SeoItem(
\trans('models.classes.' . $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.' . Str::singular($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\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str; 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 Utilisé pour la balise title de la page. * @property string $seo_title Utilisé pour la balise title de la page.
@ -36,10 +39,11 @@ use Illuminate\Support\Str;
* @property-read \App\Models\Picto $pictos Pictos Many-to-many relationship. * @property-read \App\Models\Picto $pictos Pictos Many-to-many relationship.
* @property-read \App\Models\Range $range Range Belongs to relationship. * @property-read \App\Models\Range $range Range Belongs to relationship.
*/ */
class Product extends Model class Product extends Model implements SeoInterface
{ {
use ActivityLog; use ActivityLog;
use HasFactory; use HasFactory;
use SeoTrait;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@ -168,4 +172,22 @@ class Product extends Model
{ {
return $this->belongsToMany(Picto::class); return $this->belongsToMany(Picto::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\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str; 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). * @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 $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date. * @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*/ */
class StaticPage extends Model class StaticPage extends Model implements SeoInterface
{ {
use ActivityLog; use ActivityLog;
use HasFactory; use HasFactory;
use SeoTrait;
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
@ -109,4 +113,22 @@ class StaticPage extends Model
ToolboxHelper::assertFieldIsUnique($table, 'title', $title, $id); ToolboxHelper::assertFieldIsUnique($table, 'title', $title, $id);
ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($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_choice('models.classes.' . Str::singular($this->getTable()), 1),
$this->seo_title,
$this->seo_description,
false,
\route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this),
''
);
}
} }

View file

@ -50,7 +50,11 @@ class ViewServiceProvider extends ServiceProvider
// * FORCE BOOTSTRAP PAGINATOR (or custom if in front) // * FORCE BOOTSTRAP PAGINATOR (or custom if in front)
// Early boot, request wont be filled as expected. // 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'); Paginator::defaultView('bo.modules.pagination');
} else { } else {
Paginator::useBootstrapFive(); Paginator::useBootstrapFive();

View file

@ -18,7 +18,8 @@
"mews/purifier": "^3.4", "mews/purifier": "^3.4",
"propaganistas/laravel-phone": "^5.0", "propaganistas/laravel-phone": "^5.0",
"sentry/sentry-laravel": "*", "sentry/sentry-laravel": "*",
"uwil/k8s-laravel": "*" "uwil/k8s-laravel": "*",
"uwil/seo-laravel": "^2.0"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.9.1", "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", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b72fd73d510285ac10b0b17fe78928c9", "content-hash": "2231f3e8a4eba50d8cab64366c6dcfb1",
"packages": [ "packages": [
{ {
"name": "axlon/laravel-postal-code-validation", "name": "axlon/laravel-postal-code-validation",
@ -8811,6 +8811,53 @@
], ],
"description": "Laravel requirements for k8s" "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", "name": "vlucas/phpdotenv",
"version": "v5.5.0", "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

@ -14,5 +14,6 @@ return [
'game' => 'jeu|jeux', 'game' => 'jeu|jeux',
'klub_bloc' => 'bloc klub', 'klub_bloc' => 'bloc klub',
'historicalMilestone' => 'jalon historique', 'historicalMilestone' => 'jalon historique',
'seo' => 'contenu SEO|contenus SEO'
] ]
]; ];

View file

@ -285,6 +285,7 @@ return [
'third_image' => 'troisième image', 'third_image' => 'troisième image',
'title_line1' => 'première ligne du titre', 'title_line1' => 'première ligne du titre',
'title_line2' => 'deuxième ligne du titre', 'title_line2' => 'deuxième ligne du titre',
'type' => 'type',
'unpublish_at' => 'date de fin de publication', 'unpublish_at' => 'date de fin de publication',
'url' => 'url', 'url' => 'url',
], ],

View file

@ -6,6 +6,12 @@
{{ __('Accueil') }} {{ __('Accueil') }}
</a> </a>
</li> </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>
<li class="nav-item"> <li class="nav-item">
<div class="dropdown"> <div class="dropdown">
<a class="nav-link dropdown-toggle @if (request()->routeIs('bo.static_pages.*') || request()->routeIs('bo.commitmentpages.*') || request()->routeIs('bo.klubblocs.*')) active @endif" data-bs-toggle="dropdown" type="button" <a class="nav-link dropdown-toggle @if (request()->routeIs('bo.static_pages.*') || request()->routeIs('bo.commitmentpages.*') || request()->routeIs('bo.klubblocs.*')) active @endif" data-bs-toggle="dropdown" type="button"

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">
<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">
<th scope="row">{{ str($seoItem->type)->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 !== '#')
<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

@ -216,3 +216,11 @@ Breadcrumbs::for('bo.historicalmilestones.duplicate', function (Generator $trail
$trail->parent('bo.historicalmilestones.index'); $trail->parent('bo.historicalmilestones.index');
$trail->push(Str::ucfirst(trans('crud.actions.duplicate'))); $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')
);
});