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 21cac44..22969e4 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,8 @@
"orchestra/testbench": "^6.23",
"nunomaduro/larastan": "^1.0",
"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 d68a98f..e612246 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.
@@ -179,6 +181,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