turahe/seotools

Laravel 和 Lumen 的 SEO 工具

v1.2.0 2024-05-24 08:41 UTC

This package is auto-updated.

Last update: 2024-09-24 09:33:35 UTC


README

We stand with Palestine

Latest Stable Version Total Downloads Latest Unstable Version License PHP Version Require PHP Composer

此包可自动生成有效的元标签,无需初始配置,同时提供简单但强大的 API 以便工作。

特性

  • 友好的简单界面
  • 易于设置标题和元标签
  • 易于设置 Twitter Cards 和 Open Graph 的元标签
  • 易于设置 JSON Linked Data
  • 易于设置 PWA(渐进式网页应用)

安装

1 - 依赖

第一步是使用 composer 安装包并自动更新您的 composer.json 文件,您可以通过运行以下命令来完成此操作

composer require turahe/seotools

注意:如果您正在使用 Laravel 5.5,步骤 2 和 3(提供者和别名)是不必要的。SEOTools 支持 Laravel 新的 Package Discovery

2 - 提供者

您需要更新您的应用程序配置以注册包,以便它可以被 Laravel 加载,只需更新您的 config/app.php 文件,在 'providers' 部分的末尾添加以下代码即可

config/app.php

<?php

return [
    // ...
    'providers' => [
        Turahe\SEOTools\Providers\SEOToolsServiceProvider::class,
        // ...
    ],
    // ...
];

Lumen

转到 /bootstrap/app.php 文件并添加此行

<?php
// ...

$app = new Laravel\Lumen\Application(
    dirname(__DIR__)
);

// ...

$app->register(Turahe\SEOTools\Providers\SEOToolsServiceProvider::class);

// ...

return $app;

3 - Facades

注意:Lumen 不支持 facades。

您可以使用以下 facades 获取对 SEO 工具服务的访问权限

  • Turahe\SEOTools\Facades\Tools
  • Turahe\SEOTools\Facades\OpenGraph
  • Turahe\SEOTools\Facades\TwitterCard
  • Turahe\SEOTools\Facades\JsonLd
  • Turahe\SEOTools\Facades\JsonLdMulti
  • Turahe\SEOTools\Facades\SEOTools
  • Turahe\SEOTools\Facades\PWA

您可以在 config/app.php 文件中为这些 facades 设置简短的别名。例如

<?php

return [
    // ...
    'aliases' => [
        'Meta'       => Turahe\SEOTools\Facades\Tools::class,
        'OpenGraph'     => Turahe\SEOTools\Facades\OpenGraph::class,
        'Twitter'       => Turahe\SEOTools\Facades\TwitterCard::class,
        'JsonLd'        => Turahe\SEOTools\Facades\JsonLd::class,
        'JsonLdMulti'   => Turahe\SEOTools\Facades\JsonLdMulti::class,
        'Manifest'   => Turahe\SEOTools\Facades\PWA::class,
        // or
        'SEO' => Turahe\SEOTools\Facades\SEOTools::class,
        // ...
    ],
    // ...
];

4 配置

发布配置

在您的终端中输入

php artisan vendor:publish

php artisan vendor:publish --provider="Turahe\SEOTools\Providers\SEOToolsServiceProvider"

Lumen 不支持此命令,对于它,您应该将文件 config/seotools.php 复制到您的项目的 config/seotools.php

seotools.php 配置文件中,您可以确定默认值的属性和一些行为。

seotools.php

  • meta
    • defaults - 如果页面显示未指定任何值时显示的值。如果值为 false,则不显示任何内容。
    • webmaster - 是否为主要的网络管理员工具的标签值设置设置。如果您是 null,则不显示任何内容。
  • opengraph
    • defaults - 总是显示的属性,当没有设置其他值时则使用。 您可以添加原始配置文件中未包含的附加标签
  • twitter
    • defaults - 总是显示的属性,当没有设置其他值时则使用。 您可以添加原始配置文件中未包含的附加标签
  • json-ld
    • defaults - 总是显示的属性,当没有设置其他值时则使用。 您可以添加原始配置文件中未包含的附加标签
  • manifest
    • defaults - 总是显示的属性,当没有设置其他值时则使用。 您可以添加原始配置文件中未包含的附加标签

用法

Lumen 用法

注意:Lumen 不支持 facades。

<?php

$seotools = app('seotools');
$seotools = app('seotools.meta');
$twitter = app('seotools.twitter');
$opengraph = app('seotools.opengraph');
$jsonld = app('seotools.json-ld');
$jsonldMulti = app('seotools.json-ld-multi');
$jsonldMulti = app('seotools.pwa');
// The behavior is the same as the facade

echo app('seotools')->generate();

元标签生成器

使用 SEOMeta,您可以创建元标签添加到 head

OpenGraph 标签生成器

使用 OpenGraph,您可以创建 OpenGraph 标签添加到 head

Twitter Cards 标签生成器

使用 Twitter,您可以创建 OpenGraph 标签添加到 head

在您的控制器中

<?php

namespace App\Http\Controllers;

use Turahe\SEOTools\Facades\Tools;
use Turahe\SEOTools\Facades\OpenGraph;
use Turahe\SEOTools\Facades\TwitterCard;
use Turahe\SEOTools\Facades\JsonLd;
// OR with multi
use Turahe\SEOTools\Facades\JsonLdMulti;

// OR
use Turahe\SEOTools\Facades\SEOFriendly;

class CommomController extends Controller
{
    public function index()
    {
        SEOMeta::setTitle('Home');
        SEOMeta::setDescription('This is my page description');
        SEOMeta::setCanonical('https://codecasts.com.br/lesson');

        OpenGraph::setDescription('This is my page description');
        OpenGraph::setTitle('Home');
        OpenGraph::setUrl('http://current.url.com');
        OpenGraph::addProperty('type', 'articles');

        TwitterCard::setTitle('Homepage');
        TwitterCard::setSite('@turahe');

        JsonLd::setTitle('Homepage');
        JsonLd::setDescription('This is my page description');
        JsonLd::addImage('https://codecasts.com.br/img/logo.jpg');

        // OR

        SEOTools::setTitle('Home');
        SEOTools::setDescription('This is my page description');
        SEOTools::opengraph()->setUrl('http://current.url.com');
        SEOTools::setCanonical('https://codecasts.com.br/lesson');
        SEOTools::opengraph()->addProperty('type', 'articles');
        SEOTools::twitter()->setSite('@turahe');
        SEOTools::jsonLd()->addImage('https://codecasts.com.br/img/logo.jpg');

        $posts = Post::all();

        return view('myindex', compact('posts'));
    }

    public function show($id)
    {
        $post = Post::find($id);

        SEOMeta::setTitle($post->title);
        SEOMeta::setDescription($post->resume);
        SEOMeta::addMeta('article:published_time', $post->published_date->toW3CString(), 'property');
        SEOMeta::addMeta('article:section', $post->category, 'property');
        SEOMeta::addKeyword(['key1', 'key2', 'key3']);

        OpenGraph::setDescription($post->resume);
        OpenGraph::setTitle($post->title);
        OpenGraph::setUrl('http://current.url.com');
        OpenGraph::addProperty('type', 'article');
        OpenGraph::addProperty('locale', 'pt-br');
        OpenGraph::addProperty('locale:alternate', ['id-id', 'en-us']);

        OpenGraph::addImage($post->cover->url);
        OpenGraph::addImage($post->images->list('url'));
        OpenGraph::addImage(['url' => 'http://image.url.com/cover.jpg', 'size' => 300]);
        OpenGraph::addImage('http://image.url.com/cover.jpg', ['height' => 300, 'width' => 300]);

        JsonLd::setTitle($post->title);
        JsonLd::setDescription($post->resume);
        JsonLd::setType('Article');
        JsonLd::addImage($post->images->list('url'));

        // OR with multi

        JsonLdMulti::setTitle($post->title);
        JsonLdMulti::setDescription($post->resume);
        JsonLdMulti::setType('Article');
        JsonLdMulti::addImage($post->images->list('url'));
        if(! JsonLdMulti::isEmpty()) {
            JsonLdMulti::newJsonLd();
            JsonLdMulti::setType('WebPage');
            JsonLdMulti::setTitle('Page Article - '.$post->title);
        }

        // Namespace URI: http://ogp.me/ns/article#
        // article
        OpenGraph::setTitle('Article')
            ->setDescription('Some Article')
            ->setType('article')
            ->setArticle([
                'published_time' => 'datetime',
                'modified_time' => 'datetime',
                'expiration_time' => 'datetime',
                'author' => 'profile / array',
                'section' => 'string',
                'tag' => 'string / array'
            ]);

        // Namespace URI: http://ogp.me/ns/book#
        // book
        OpenGraph::setTitle('Book')
            ->setDescription('Some Book')
            ->setType('book')
            ->setBook([
                'author' => 'profile / array',
                'isbn' => 'string',
                'release_date' => 'datetime',
                'tag' => 'string / array'
            ]);

        // Namespace URI: http://ogp.me/ns/profile#
        // profile
        OpenGraph::setTitle('Profile')
             ->setDescription('Some Person')
            ->setType('profile')
            ->setProfile([
                'first_name' => 'string',
                'last_name' => 'string',
                'username' => 'string',
                'gender' => 'enum(male, female)'
            ]);

        // Namespace URI: http://ogp.me/ns/music#
        // music.song
        OpenGraph::setType('music.song')
            ->setMusicSong([
                'duration' => 'integer',
                'album' => 'array',
                'album:disc' => 'integer',
                'album:track' => 'integer',
                'musician' => 'array'
            ]);

        // music.album
        OpenGraph::setType('music.album')
            ->setMusicAlbum([
                'song' => 'music.song',
                'song:disc' => 'integer',
                'song:track' => 'integer',
                'musician' => 'profile',
                'release_date' => 'datetime'
            ]);

         //music.playlist
        OpenGraph::setType('music.playlist')
            ->setMusicPlaylist([
                'song' => 'music.song',
                'song:disc' => 'integer',
                'song:track' => 'integer',
                'creator' => 'profile'
            ]);

        // music.radio_station
        OpenGraph::setType('music.radio_station')
            ->setMusicRadioStation([
                'creator' => 'profile'
            ]);

        // Namespace URI: http://ogp.me/ns/video#
        // video.movie
        OpenGraph::setType('video.movie')
            ->setVideoMovie([
                'actor' => 'profile / array',
                'actor:role' => 'string',
                'director' => 'profile /array',
                'writer' => 'profile / array',
                'duration' => 'integer',
                'release_date' => 'datetime',
                'tag' => 'string / array'
            ]);

        // video.episode
        OpenGraph::setType('video.episode')
            ->setVideoEpisode([
                'actor' => 'profile / array',
                'actor:role' => 'string',
                'director' => 'profile /array',
                'writer' => 'profile / array',
                'duration' => 'integer',
                'release_date' => 'datetime',
                'tag' => 'string / array',
                'series' => 'video.tv_show'
            ]);

        // video.tv_show
        OpenGraph::setType('video.tv_show')
            ->setVideoTVShow([
                'actor' => 'profile / array',
                'actor:role' => 'string',
                'director' => 'profile /array',
                'writer' => 'profile / array',
                'duration' => 'integer',
                'release_date' => 'datetime',
                'tag' => 'string / array'
            ]);

        // video.other
        OpenGraph::setType('video.other')
            ->setVideoOther([
                'actor' => 'profile / array',
                'actor:role' => 'string',
                'director' => 'profile /array',
                'writer' => 'profile / array',
                'duration' => 'integer',
                'release_date' => 'datetime',
                'tag' => 'string / array'
            ]);

        // og:video
        OpenGraph::addVideo('http://example.com/movie.swf', [
                'secure_url' => 'https://example.com/movie.swf',
                'type' => 'application/x-shockwave-flash',
                'width' => 400,
                'height' => 300
            ]);

        // og:audio
        OpenGraph::addAudio('http://example.com/sound.mp3', [
                'secure_url' => 'https://secure.example.com/sound.mp3',
                'type' => 'audio/mpeg'
            ]);

        // og:place
        OpenGraph::setTitle('Place')
             ->setDescription('Some Place')
            ->setType('place')
            ->setPlace([
                'location:latitude' => 'float',
                'location:longitude' => 'float',
            ]);

        return view('myshow', compact('post'));
    }
}

SEOTrait

<?php

namespace App\Http\Controllers;

use Turahe\SEOTools\Traits\SEOTools as SEOToolsTrait;

class CommomController extends Controller
{
    use SEOToolsTrait;

    public function index()
    {
        $this->seo()->setTitle('Home');
        $this->seo()->setDescription('This is my page description');
        $this->seo()->opengraph()->setUrl('http://current.url.com');
        $this->seo()->opengraph()->addProperty('type', 'articles');
        $this->seo()->twitter()->setSite('@turahe');
        $this->seo()->jsonLd()->setType('Article');

        $posts = Post::all();

        return view('myindex', compact('posts'));
    }
}

在您的视图中

技巧提示:传递参数 true 以获取压缩代码并减小文件大小。

<html>
<head>
    {!! SEOMeta::generate() !!}
    {!! OpenGraph::generate() !!}
    {!! Twitter::generate() !!}
    {!! JsonLd::generate() !!}
    // OR with multi
    {!! JsonLdMulti::generate() !!}

    <!-- OR -->
    {!! SEO::generate() !!}

    <!-- MINIFIED -->
    {!! SEO::generate(true) !!}

    <!-- LUMEN -->
    {!! app('seotools')->generate() !!}
</head>
<body>

</body>
</html>
<html>
<head>
    <title>Title - My Title Website</title>
    <meta name='description' itemprop='description' content='description...' />
    <meta name='keywords' content='key1, key2, key3' />
    <meta property='article:published_time' content='2015-01-31T20:30:11-02:00' />
    <meta property='article:section' content='news' />

    <meta property="og:description"content="description..." />
    <meta property="og:title"content="Title" />
    <meta property="og:url"content="http://current.url.com" />
    <meta property="og:type"content="article" />
    <meta property="og:locale"content="pt-br" />
    <meta property="og:locale:alternate"content="id-id" />
    <meta property="og:locale:alternate"content="en-us" />
    <meta property="og:site_name"content="name" />
    <meta property="og:image"content="http://image.url.com/cover.jpg" />
    <meta property="og:image"content="http://image.url.com/img1.jpg" />
    <meta property="og:image"content="http://image.url.com/img2.jpg" />
    <meta property="og:image"content="http://image.url.com/img3.jpg" />
    <meta property="og:image:url"content="http://image.url.com/cover.jpg" />
    <meta property="og:image:size"content="300" />

    <meta name="twitter:card"content="summary" />
    <meta name="twitter:title"content="Title" />
    <meta name="twitter:site"content="@turahe" />

    <script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","name":"Title - My Title Website"}</script>
    <!-- OR with multi -->
    <script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","name":"Title - My Title Website"}</script>
    <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"Title - My Title Website"}</script>
</head>
<body>

</body>
</html>

API(SEOMeta)

<?php

use Turahe\SEOTools\Facades\SEOMeta;

SEOMeta::addKeyword($keyword);
SEOMeta::addMeta($meta, $value = null, $name = 'name');
SEOMeta::addAlternateLanguage($lang, $url);
SEOMeta::addAlternateLanguages(array $languages);
SEOMeta::setTitleSeparator($separator);
SEOMeta::setTitle($title);
SEOMeta::setTitleDefault($default);
SEOMeta::setDescription($description);
SEOMeta::setKeywords($keywords);
SEOMeta::setRobots($robots);
SEOMeta::setCanonical($url);
SEOMeta::setPrev($url);
SEOMeta::setNext($url);
SEOMeta::removeMeta($key);

// You can chain methods
SEOMeta::setTitle($title)
            ->setDescription($description)
            ->setKeywords($keywords)
            ->addKeyword($keyword)
            ->addMeta($meta, $value);

// Retrieving data
SEOMeta::getTitle();
SEOMeta::getTitleSession();
SEOMeta::getTitleSeparator();
SEOMeta::getKeywords();
SEOMeta::getDescription();
SEOMeta::getCanonical($url);
SEOMeta::getPrev($url);
SEOMeta::getNext($url);
SEOMeta::getRobots();
SEOMeta::reset();

SEOMeta::generate();

API(OpenGraph)

<?php

use Turahe\SEOTools\Facades\OpenGraph;

OpenGraph::addProperty($key, $value); // value can be string or array
OpenGraph::addImage($url); // add image url
OpenGraph::addImages($url); // add an array of url images
OpenGraph::setTitle($title); // define title
OpenGraph::setDescription($description);  // define description
OpenGraph::setUrl($url); // define url
OpenGraph::setSiteName($name); //define site_name

// You can chain methods
OpenGraph::addProperty($key, $value)
            ->addImage($url)
            ->addImages($url)
            ->setTitle($title)
            ->setDescription($description)
            ->setUrl($url)
            ->setSiteName($name);

// Generate html tags
OpenGraph::generate();

API(TwitterCard)

<?php

use Turahe\SEOTools\Facades\TwitterCard;

TwitterCard::addValue($key, $value); // value can be string or array
TwitterCard::setType($type); // type of twitter card tag
TwitterCard::setTitle($type); // title of twitter card tag
TwitterCard::setSite($type); // site of twitter card tag
TwitterCard::setDescription($type); // description of twitter card tag
TwitterCard::setUrl($type); // url of twitter card tag
TwitterCard::setImage($url); // add image url

// You can chain methods
TwitterCard::addValue($key, $value)
            ->setType($type)
            ->setImage($url)
            ->setTitle($title)
            ->setDescription($description)
            ->setUrl($url)
            ->setSite($name);

// Generate html tags
TwitterCard::generate();

API(JsonLd)

<?php

use Turahe\SEOTools\Facades\JsonLd;

JsonLd::addValue($key, $value); // value can be string or array
JsonLd::setType($type); // type of twitter card tag
JsonLd::setTitle($type); // title of twitter card tag
JsonLd::setSite($type); // site of twitter card tag
JsonLd::setDescription($type); // description of twitter card tag
JsonLd::setUrl($type); // url of twitter card tag
JsonLd::setImage($url); // add image url

// You can chain methods
JsonLd::addValue($key, $value)
    ->setType($type)
    ->setImage($url)
    ->setTitle($title)
    ->setDescription($description)
    ->setUrl($url)
    ->setSite($name);

// Generate html tags
JsonLd::generate();

API(JsonLdMulti)

<?php

use Turahe\SEOTools\Facades\JsonLdMulti;

JsonLdMulti::newJsonLd(); // create a new JsonLd group
JsonLdMulti::isEmpty(); // check if the current JsonLd group is empty
JsonLdMulti::select($index); // choose the JsonLd group that will be edited by the methods below
JsonLdMulti::addValue($key, $value); // value can be string or array
JsonLdMulti::setType($type); // type of twitter card tag
JsonLdMulti::setTitle($type); // title of twitter card tag
JsonLdMulti::setSite($type); // site of twitter card tag
JsonLdMulti::setDescription($type); // description of twitter card tag
JsonLdMulti::setUrl($type); // url of twitter card tag
JsonLdMulti::setImage($url); // add image url

// You can chain methods
JsonLdMulti::addValue($key, $value)
    ->setType($type)
    ->setImage($url)
    ->setTitle($title)
    ->setDescription($description)
    ->setUrl($url)
    ->setSite($name);
// You can add an other group
if(! JsonLdMulti::isEmpty()) {
    JsonLdMulti::newJsonLd()
        ->setType($type)
        ->setImage($url)
        ->setTitle($title)
        ->setDescription($description)
        ->setUrl($url)
        ->setSite($name);
}
// Generate html tags
JsonLdMulti::generate();
// You will have retrieve <script content="application/ld+json"/>

API(SEO)

方便访问所有SEO提供商

<?php

use Turahe\SEOTools\Facades\SEOTools;

SEOTools::seotools();
SEOTools::twitter();
SEOTools::opengraph();
SEOTools::jsonLd();
SEOTools::manifest();

SEOTools::setTitle($title);
SEOTools::getTitle($session = false);
SEOTools::setDescription($description);
SEOTools::setCanonical($url);
SEOTools::addImages($urls);

故障排除

在运行Laravel测试服务器时

  1. 验证 /manifest.json 是否正在提供
  2. 验证 /serviceworker.js 是否正在提供
  3. 使用Chrome开发者工具中的“应用程序”选项卡来验证渐进式Web应用程序是否正确配置。
  4. 使用“添加到主屏幕”链接在应用程序选项卡中验证您是否可以成功添加应用程序。

服务工作者

默认情况下,此应用程序实现的服务工作者是

var staticCacheName = "pwa-v" + new Date().getTime();
var filesToCache = [
    '/offline',
    '/css/app.css',
    '/js/app.js',
    '/images/icons/icon-72x72.png',
    '/images/icons/icon-96x96.png',
    '/images/icons/icon-128x128.png',
    '/images/icons/icon-144x144.png',
    '/images/icons/icon-152x152.png',
    '/images/icons/icon-192x192.png',
    '/images/icons/icon-384x384.png',
    '/images/icons/icon-512x512.png',
    '/images/icons/splash-640x1136.png',
    '/images/icons/splash-750x1334.png',
    '/images/icons/splash-1242x2208.png',
    '/images/icons/splash-1125x2436.png',
    '/images/icons/splash-828x1792.png',
    '/images/icons/splash-1242x2688.png',
    '/images/icons/splash-1536x2048.png',
    '/images/icons/splash-1668x2224.png',
    '/images/icons/splash-1668x2388.png',
    '/images/icons/splash-2048x2732.png'
];

// Cache on install
self.addEventListener("install", event => {
    this.skipWaiting();
    event.waitUntil(
        caches.open(staticCacheName)
            .then(cache => {
                return cache.addAll(filesToCache);
            })
    )
});

// Clear cache on activate
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames
                    .filter(cacheName => (cacheName.startsWith("pwa-")))
                    .filter(cacheName => (cacheName !== staticCacheName))
                    .map(cacheName => caches.delete(cacheName))
            );
        })
    );
});

// Serve from Cache
self.addEventListener("fetch", event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                return response || fetch(event.request);
            })
            .catch(() => {
                return caches.match('offline');
            })
    )
});

要自定义服务工作者功能,更新 public/serviceworker.js

离线视图

默认情况下,离线视图在 resources/views/vendor/seotools/offline.blade.php 中实现

@extends('layouts.app')

@section('content')

    <h1>You are currently not connected to any networks.</h1>

@endsection