Skip to content

Commit c7a9e90

Browse files
committed
fix: do not escape image URLs for OG or Twitter
1 parent fb8f41b commit c7a9e90

File tree

7 files changed

+51
-7
lines changed

7 files changed

+51
-7
lines changed

src/Support/OpenGraphTag.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33
namespace RalphJSmit\Laravel\SEO\Support;
44

55
use Illuminate\Support\Collection;
6+
use Illuminate\Support\HtmlString;
67

78
class OpenGraphTag extends Tag
89
{
910
public string $tag = 'meta';
1011

1112
public function __construct(
1213
string $property,
13-
string $content,
14+
string | HtmlString $content,
1415
) {
1516
$this->attributes['property'] = $property;
1617
$this->attributes['content'] = $content;
1718

1819
$this->attributesPipeline[] = function (Collection $collection) {
19-
return $collection->mapWithKeys(function ($value, $key) {
20+
return $collection->mapWithKeys(function (mixed $value, string $key) {
2021
if ($key === 'property') {
2122
$value = 'og:' . $value;
2223
}

src/Support/TwitterCardTag.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33
namespace RalphJSmit\Laravel\SEO\Support;
44

55
use Illuminate\Support\Collection;
6+
use Illuminate\Support\HtmlString;
67

78
class TwitterCardTag extends Tag
89
{
910
public string $tag = 'meta';
1011

1112
public function __construct(
1213
string $name,
13-
string $content,
14+
string | HtmlString $content,
1415
) {
1516
$this->attributes['name'] = $name;
1617
$this->attributes['content'] = $content;
1718

1819
$this->attributesPipeline[] = function (Collection $collection) {
19-
return $collection->mapWithKeys(function ($value, $key) {
20+
return $collection->mapWithKeys(function (mixed $value, string $key) {
2021
if ($key === 'name') {
2122
$value = 'twitter:' . $value;
2223
}

src/Tags/OpenGraphTags.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Contracts\Support\Renderable;
66
use Illuminate\Support\Collection;
7+
use Illuminate\Support\HtmlString;
78
use RalphJSmit\Laravel\SEO\Support\MetaContentTag;
89
use RalphJSmit\Laravel\SEO\Support\OpenGraphTag;
910
use RalphJSmit\Laravel\SEO\Support\RenderableCollection;
@@ -32,7 +33,7 @@ public static function initialize(SEOData $SEOData): static
3233
}
3334

3435
if ($SEOData->image) {
35-
$collection->push(new OpenGraphTag('image', $SEOData->image));
36+
$collection->push(new OpenGraphTag('image', new HtmlString($SEOData->image)));
3637

3738
if ($SEOData->imageMeta) {
3839
$collection

src/Tags/TwitterCard/Summary.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Contracts\Support\Renderable;
66
use Illuminate\Support\Collection;
7+
use Illuminate\Support\HtmlString;
78
use RalphJSmit\Laravel\SEO\Support\RenderableCollection;
89
use RalphJSmit\Laravel\SEO\Support\SEOData;
910
use RalphJSmit\Laravel\SEO\Support\TwitterCardTag;
@@ -37,7 +38,7 @@ public static function initialize(SEOData $SEOData): static
3738
$collection->push(new TwitterCardTag('card', 'summary'));
3839

3940
if ($SEOData->image) {
40-
$collection->push(new TwitterCardTag('image', $SEOData->image));
41+
$collection->push(new TwitterCardTag('image', new HtmlString($SEOData->image)));
4142

4243
if ($SEOData->imageMeta) {
4344
$collection

src/Tags/TwitterCard/SummaryLargeImage.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Contracts\Support\Renderable;
66
use Illuminate\Support\Collection;
7+
use Illuminate\Support\HtmlString;
78
use RalphJSmit\Laravel\SEO\Support\RenderableCollection;
89
use RalphJSmit\Laravel\SEO\Support\SEOData;
910
use RalphJSmit\Laravel\SEO\Support\TwitterCardTag;
@@ -37,7 +38,7 @@ public static function initialize(SEOData $SEOData): static
3738
$collection->push(new TwitterCardTag('card', 'summary_large_image'));
3839

3940
if ($SEOData->image) {
40-
$collection->push(new TwitterCardTag('image', $SEOData->image));
41+
$collection->push(new TwitterCardTag('image', new HtmlString($SEOData->image)));
4142

4243
if ($SEOData->imageMeta) {
4344
$collection

tests/Feature/Tags/OpenGraphTagsTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,21 @@
153153
get(route('seo.test-page', ['page' => $page]))
154154
->assertSee('<meta property="og:title" content="My page title - A &amp; B">', false);
155155
});
156+
157+
it('will not escape the image URL query parameters', function () {
158+
config()->set('seo.title.suffix', ' | Laravel SEO');
159+
config()->set('seo.description.fallback', 'Fallback description');
160+
161+
$page = Page::create();
162+
163+
$page::$overrides = [
164+
'title' => 'Test Page',
165+
'image' => $url = 'https://website.test/images/xSVtl6ZF7fNuZIoXkZbzI2EzoAD.jpg?h=800&fit=contain&q=80&fm=webp',
166+
];
167+
168+
get(route('seo.test-page', ['page' => $page]))
169+
->assertSee('<meta property="og:image" content="' . $url . '">', false)
170+
->assertDontSee('<meta property="og:image:width"', false)
171+
->assertDontSee('<meta property="og:image:height"', false)
172+
->assertDontSee('twitter:site'); // We should not display an empty '@' username.
173+
});

tests/Feature/Tags/TwitterCardSummaryTagsTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,27 @@
7979
['summary_large_image', 'images/twitter-3597x1799.jpg', '3597', '1799'],
8080
]);
8181

82+
it('will not escape the image URL query parameters', function () {
83+
config()->set('seo.title.suffix', ' | Laravel SEO');
84+
config()->set('seo.description.fallback', 'Fallback description');
85+
86+
$page = Page::create();
87+
88+
$page::$overrides = [
89+
'title' => 'Test Page',
90+
'image' => $url = 'https://website.test/images/xSVtl6ZF7fNuZIoXkZbzI2EzoAD.jpg?h=800&fit=contain&q=80&fm=webp',
91+
];
92+
93+
get(route('seo.test-page', ['page' => $page]))
94+
->assertSee('<meta name="twitter:card" content="summary_large_image">', false)
95+
->assertSee('<meta name="twitter:title" content="Test Page | Laravel SEO">', false)
96+
->assertSee('<meta name="twitter:description" content="Fallback description">', false)
97+
->assertSee('<meta name="twitter:image" content="' . $url . '">', false)
98+
->assertDontSee('<meta name="twitter:image:width"', false)
99+
->assertDontSee('<meta name="twitter:image:height"', false)
100+
->assertDontSee('twitter:site'); // We should not display an empty '@' username.
101+
});
102+
82103
it('will not render the Twitter Card summary_large_image for too large or small images', function (string $imagePath) {
83104
$page = Page::create();
84105

0 commit comments

Comments
 (0)