🎉 feat(seo): add Laravel SEO package and create SEO migration for better site optimization.

This commit is contained in:
fsociety
2024-10-24 19:18:30 +02:00
parent 06c43501a0
commit 05773cb5b3
6 changed files with 313 additions and 5 deletions

View File

@@ -23,6 +23,7 @@
"livewire/volt": "^1.6",
"openspout/openspout": "^4.24",
"power-components/livewire-powergrid": "^5.10",
"ralphjsmit/laravel-seo": "^1.6",
"sentry/sentry-laravel": "^4.9",
"simplesoftwareio/simple-qrcode": "^4.2",
"spatie/image": "^3.7",

153
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": "84b5a6a420aba2ae3bf94bad89b46a41",
"content-hash": "bda4dccb94a2861dc6ff18410d22a5ec",
"packages": [
{
"name": "akuechler/laravel-geoly",
@@ -4966,6 +4966,157 @@
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "ralphjsmit/laravel-helpers",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/ralphjsmit/laravel-helpers.git",
"reference": "840b4979a92c7b676d25f56430823f12481f2914"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralphjsmit/laravel-helpers/zipball/840b4979a92c7b676d25f56430823f12481f2914",
"reference": "840b4979a92c7b676d25f56430823f12481f2914",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.4",
"illuminate/contracts": "^8.73|^9.0|^10.0|^11.0",
"php": "^8.0",
"spatie/laravel-package-tools": "^1.9.2"
},
"require-dev": {
"livewire/livewire": "^2.9|^3.4",
"nesbot/carbon": "^2.66|^3.0",
"nunomaduro/collision": "^5.10|^6.1|^7.0|^8.0",
"orchestra/testbench": "^6.22|^7.0|^8.0|^9.0",
"pestphp/pest": "^1.21|^2.34",
"pestphp/pest-plugin-laravel": "^1.1|^2.3",
"phpunit/phpunit": "^9.5|^10.5",
"spatie/invade": "^1.0|^2.0",
"spatie/laravel-ray": "^1.26"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"RalphJSmit\\Helpers\\HelpersServiceProvider"
],
"aliases": {
"Helpers": "RalphJSmit\\Helpers\\Facades\\Helpers"
}
}
},
"autoload": {
"files": [
"src/Laravel/Support/helpers.php",
"src/helpers.php"
],
"psr-4": {
"RalphJSmit\\Helpers\\": "src",
"RalphJSmit\\Helpers\\Database\\Factories\\": "database/factories"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph J. Smit",
"email": "rjs@ralphjsmit.com",
"role": "Developer"
}
],
"description": "A package containing handy helpers for your Laravel-application.",
"homepage": "https://github.com/ralphjsmit/laravel-helpers",
"keywords": [
"laravel",
"laravel-helpers",
"ralphjsmit"
],
"support": {
"issues": "https://github.com/ralphjsmit/laravel-helpers/issues",
"source": "https://github.com/ralphjsmit/laravel-helpers/tree/1.9.0"
},
"time": "2024-03-14T08:30:30+00:00"
},
{
"name": "ralphjsmit/laravel-seo",
"version": "1.6.3",
"source": {
"type": "git",
"url": "https://github.com/ralphjsmit/laravel-seo.git",
"reference": "f22d0a2982f0d5162b57609b56537643d562b67d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralphjsmit/laravel-seo/zipball/f22d0a2982f0d5162b57609b56537643d562b67d",
"reference": "f22d0a2982f0d5162b57609b56537643d562b67d",
"shasum": ""
},
"require": {
"illuminate/contracts": "^9.0|^10.0|^11.0",
"php": "^8.0",
"ralphjsmit/laravel-helpers": "^1.9",
"spatie/laravel-package-tools": "^1.9.2"
},
"require-dev": {
"laravel/pint": "^1.16",
"nesbot/carbon": "^2.66|^3.0",
"nunomaduro/collision": "^5.10|^6.0|^7.0|^8.0",
"orchestra/testbench": "^7.0|^8.0|^9.0",
"pestphp/pest": "^1.21|^2.0",
"pestphp/pest-plugin-laravel": "^1.1|^2.0",
"phpunit/phpunit": "^9.5|^10.5",
"spatie/laravel-ray": "^1.26",
"spatie/pest-plugin-test-time": "^1.0|^2.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"RalphJSmit\\Laravel\\SEO\\LaravelSEOServiceProvider"
],
"aliases": {
"SEOManager": "RalphJSmit\\Laravel\\SEO\\Facades\\SEOManager"
}
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"RalphJSmit\\Laravel\\SEO\\": "src",
"RalphJSmit\\Laravel\\SEO\\Database\\Factories\\": "database/factories"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph J. Smit",
"email": "rjs@ralphjsmit.com",
"role": "Developer"
}
],
"description": "A package to handle the SEO in any Laravel application, big or small.",
"homepage": "https://github.com/ralphjsmit/laravel-seo",
"keywords": [
"laravel",
"laravel-seo",
"ralphjsmit"
],
"support": {
"issues": "https://github.com/ralphjsmit/laravel-seo/issues",
"source": "https://github.com/ralphjsmit/laravel-seo/tree/1.6.3"
},
"time": "2024-08-30T11:58:06+00:00"
},
{
"name": "ramsey/collection",
"version": "2.0.0",

122
config/seo.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
use RalphJSmit\Laravel\SEO\Models\SEO;
return [
/**
* The SEO model. You can use this setting to override the model used by the package.
* Make sure to always extend the old model, so that you'll not lose functionality during upgrades.
*/
'model' => SEO::class,
/**
* Use this setting to specify the site name that will be used in OpenGraph tags.
*/
'site_name' => null,
/**
* Use this setting to specify the path to the sitemap of your website. This exact path will outputted, so
* you can use both a hardcoded url and a relative path. We recommend the latter.
*
* Example: '/storage/sitemap.xml'
* Do not forget the slash at the start. This will tell the search engine that the path is relative
* to the root domain and not relative to the current URL. The `spatie/laravel-sitemap` package
* is a great package to generate sitemaps for your application.
*/
'sitemap' => null,
/**
* Use this setting to specify whether you want self-referencing `<link rel="canonical" href="$url">` tags to
* be added to the head of every page. There has been some debate whether this a good practice, but experts
* from Google and Yoast say that this is the best strategy.
* See https://yoast.com/rel-canonical/.
*/
'canonical_link' => true,
'robots' => [
/**
* Use this setting to specify the default value of the robots meta tag. `<meta name="robots" content="noindex">`
* Overwrite it with the robots attribute of the SEOData object. `SEOData->robots = 'noindex, nofollow'`
* "max-snippet:-1" Use n chars (-1: Search engine chooses) as a search result snippet.
* "max-image-preview:large" Max size of a preview in search results.
* "max-video-preview:-1" Use max seconds (-1: There is no limit) as a video snippet in search results.
* See https://developers.google.com/search/docs/advanced/robots/robots_meta_tag
* Default: 'max-snippet:-1, max-image-preview:large, max-video-preview:-1'
*/
'default' => 'max-snippet:-1,max-image-preview:large,max-video-preview:-1',
/**
* Force set the robots `default` value and make it impossible to overwrite it. (e.g. via SEOData->robots)
* Use case: You need to set `noindex, nofollow` for the entire website without exception.
* Default: false
*/
'force_default' => false,
],
/**
* Use this setting to specify the path to the favicon for your website. The url to it will be generated using the `secure_url()` function,
* so make sure to make the favicon accessibly from the `public` folder.
*
* You can use the following filetypes: ico, png, gif, jpeg, svg.
*/
'favicon' => null,
'title' => [
/**
* Use this setting to let the package automatically infer a title from the url, if no other title
* was given. This will be very useful on pages where you don't have an Eloquent model for, or where you
* don't want to hardcode the title.
*
* For example, if you have a page with the url '/foo/about-me', we'll automatically set the title to 'About me' and append the site suffix.
*/
'infer_title_from_url' => true,
/**
* Use this setting to provide a suffix that will be added after the title on each page.
* If you don't want a suffix, you should specify an empty string.
*/
'suffix' => '',
/**
* Use this setting to provide a custom title for the homepage. We will not use the suffix on the homepage,
* so you'll need to add the suffix manually if you want that. If set to null, we'll determine the title
* just like the other pages.
*/
'homepage_title' => null,
],
'description' => [
/**
* Use this setting to specify a fallback description, which will be used on places
* where we don't have a description set via an associated ->seo model or via
* the ->getDynamicSEOData() method.
*/
'fallback' => null,
],
'image' => [
/**
* Use this setting to specify a fallback image, which will be used on places where you
* don't have an image set via an associated ->seo model or via the ->getDynamicSEOData() method.
* This should be a path to an image. The url to the path is generated using the `secure_url()` function
* (`secure_url($yourProvidedPath)`), so make sure the image is accessible from the public folder.
*/
'fallback' => null,
],
'author' => [
/**
* Use this setting to specify a fallback author, which will be used on places where you
* don't have an author set via an associated ->seo model or via the ->getDynamicSEOData() method.
*/
'fallback' => null,
],
'twitter' => [
/**
* Use this setting to enter your username and include that with the Twitter Card tags.
* Enter the username like 'yourUserName', so without the '@'.
*/
'@username' => null,
],
];

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('seo', function (Blueprint $table) {
$table->id();
$table->morphs('model');
$table->longText('description')->nullable();
$table->string('title')->nullable();
$table->string('image')->nullable();
$table->string('author')->nullable();
$table->string('robots')->nullable();
$table->string('canonical_url')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('seo');
}
};

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{!! seo($seo ?? null) !!}
<title>{{ $title ?? 'Page Title' }}</title>
@livewireStyles

View File

@@ -3,6 +3,7 @@
use App\Livewire\Forms\VoteForm;
use App\Models\Vote;
use Livewire\Volt\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use swentel\nostr\Filter\Filter;
use swentel\nostr\Key\Key;
use swentel\nostr\Message\RequestMessage;
@@ -10,9 +11,8 @@ use swentel\nostr\Relay\Relay;
use swentel\nostr\Request\Request;
use swentel\nostr\Subscription\Subscription;
use function Laravel\Folio\{middleware};
use function Laravel\Folio\name;
use function Livewire\Volt\{state, mount, on, computed, form};
use function Laravel\Folio\{middleware, name};
use function Livewire\Volt\{state, mount, on, computed, form, with};
name('association.projectSupport.item');
@@ -105,7 +105,9 @@ $notApprove = function () {
?>
<x-layouts.app title="{{ $projectProposal->name }}">
<x-layouts.app title="{{ $projectProposal->name }}"
:seo="new SEOData(image: $projectProposal->getFirstMediaUrl('main'), description: str($projectProposal->description)->limit(100, '...', true))">
>
@volt
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full" x-data="nostrDefault(@this)" x-cloak
x-show="isAllowed">