diff --git a/README.md b/README.md index de69c8e..37b3f62 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,18 @@ When a value is set specifically for Twitter, it will be prioritized over the ge seo()->twitterTitle('About us') ``` +### Favicons + +By default, no favicon links will be included. You can manually enable the extension by calling: + +```php +seo()->favicon('path/to/logo.png'); +``` + +We'll generate a 32x32px `public/favicon.ico` & `public/favicon.png` icon. This should be sufficient for most cases. + +**Please keep in mind that you need to install the [imagick](https://pecl.php.net/package/imagick) php extension and [intervention/image](http://image.intervention.io/) composer package.** + ### Defaults To configure default values, call the methods with the `default` argument: diff --git a/assets/views/components/extensions/favicon.blade.php b/assets/views/components/extensions/favicon.blade.php new file mode 100644 index 0000000..bafadca --- /dev/null +++ b/assets/views/components/extensions/favicon.blade.php @@ -0,0 +1,2 @@ + + diff --git a/composer.json b/composer.json index 6c0e997..6f0e1a6 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "orchestra/testbench": "^6.9", "nunomaduro/larastan": "^0.6.10", "pestphp/pest": "^1.2", - "pestphp/pest-plugin-laravel": "^1.0" + "pestphp/pest-plugin-laravel": "^1.0", + "intervention/image": "^2.7" }, "extra": { "laravel": { diff --git a/src/SEOManager.php b/src/SEOManager.php index d036034..6af7578 100644 --- a/src/SEOManager.php +++ b/src/SEOManager.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace ArchTech\SEO; use Closure; +use Exception; use Illuminate\Support\Str; +use Intervention\Image\ImageManager; /** * @method $this title(string $title = null, ...$args) Set the title. @@ -176,6 +178,40 @@ class SEOManager return $this->set('image', "https://s.useflipp.com/{$template}.png?s={$signature}&v={$query}"); } + /** Enable favicon extension. */ + public function favicon(string $path): static + { + if (! class_exists(ImageManager::class)) { + throw new Exception('Intervention not available, please run `composer require intervention/image`'); + } + + $this->extensions['favicon'] = true; + + $doesntHaveFavicon = ! file_exists(public_path('favicon.ico')); + $sourceIconDoesntExist = ! file_exists($path); + + if ($sourceIconDoesntExist) { + throw new Exception("Given icon path `{$path}` does not exist."); + } + + if ($doesntHaveFavicon) { + // GD driver doesn't support .ico, that's why we use ImageMagick. + $manager = new ImageManager(['driver' => 'imagick']); + + $manager + ->make($path) + ->resize(32, 32) + ->save(public_path('favicon.ico')); + + $manager + ->make($path) + ->resize(32, 32) + ->save(public_path('favicon.png')); + } + + return $this; + } + /** Append canonical URL tags to the document head. */ public function withUrl(): static { diff --git a/tests/Pest/FaviconTest.php b/tests/Pest/FaviconTest.php new file mode 100644 index 0000000..50d47cc --- /dev/null +++ b/tests/Pest/FaviconTest.php @@ -0,0 +1,14 @@ +favicon('i-dont-exist.png'); +})->throws(Exception::class, 'Given icon path `i-dont-exist.png` does not exist.'); + +test('it should generate two favicons', function () { + seo()->favicon(__DIR__ . '/../stubs/logo.png'); + + assertFileExists(public_path('favicon.ico')); + assertFileExists(public_path('favicon.png')); +}); diff --git a/tests/stubs/logo.png b/tests/stubs/logo.png new file mode 100644 index 0000000..afac3bb Binary files /dev/null and b/tests/stubs/logo.png differ