Skip to content

Commit 1bacf0a

Browse files
committed
Add a new simplified image front matter schema
1 parent 4afcbf6 commit 1bacf0a

File tree

8 files changed

+124
-6
lines changed

8 files changed

+124
-6
lines changed

packages/framework/resources/views/components/post/image.blade.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
<figure aria-label="Cover image" itemprop="image" itemscope itemtype="https://schema.org/ImageObject" role="doc-cover">
77
<img src="{{ $image->getSource() }}" alt="{{ $image->getAltText() ?? '' }}" title="{{ $image->getTitleText() ?? '' }}" itemprop="image" class="mb-0">
88
<figcaption aria-label="Image caption" itemprop="caption">
9+
@if($image->hasCaption())
10+
<span>{{ $image->getCaption() }}</span>
11+
@endif
12+
913
@if($image->hasAuthorName())
1014
<span>Image by</span>
1115
<span itemprop="creator" itemscope="" itemtype="https://schema.org/Person">

packages/framework/src/Framework/Factories/FeaturedImageFactory.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,25 @@ class FeaturedImageFactory extends Concerns\PageDataFactory implements FeaturedI
2828
protected readonly ?string $copyrightText;
2929
protected readonly ?string $licenseName;
3030
protected readonly ?string $licenseUrl;
31+
protected readonly ?string $caption;
3132

3233
public function __construct(
3334
private readonly FrontMatter $matter,
3435
private readonly ?string $filePath = null,
3536
) {
3637
$this->source = $this->makeSource();
37-
$this->altText = $this->getStringMatter('image.altText');
38+
$this->altText = $this->getStringMatter('image.altText') ?? $this->getStringMatter('image.alt');
3839
$this->titleText = $this->getStringMatter('image.titleText');
3940
$this->authorName = $this->getStringMatter('image.authorName');
4041
$this->authorUrl = $this->getStringMatter('image.authorUrl');
4142
$this->copyrightText = $this->getStringMatter('image.copyright');
4243
$this->licenseName = $this->getStringMatter('image.licenseName');
4344
$this->licenseUrl = $this->getStringMatter('image.licenseUrl');
45+
$this->caption = $this->getStringMatter('image.caption');
4446
}
4547

4648
/**
47-
* @return array{source: string, altText: string|null, titleText: string|null, authorName: string|null, authorUrl: string|null, copyrightText: string|null, licenseName: string|null, licenseUrl: string|null}
49+
* @return array{source: string, altText: string|null, titleText: string|null, authorName: string|null, authorUrl: string|null, copyrightText: string|null, licenseName: string|null, licenseUrl: string|null, caption: string|null}
4850
*/
4951
public function toArray(): array
5052
{
@@ -57,6 +59,7 @@ public function toArray(): array
5759
'copyrightText' => $this->copyrightText,
5860
'licenseName' => $this->licenseName,
5961
'licenseUrl' => $this->licenseUrl,
62+
'caption' => $this->caption,
6063
];
6164
}
6265

packages/framework/src/Framework/Features/Blogging/Models/FeaturedImage.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ public function __construct(
5858
protected readonly ?string $authorUrl = null,
5959
protected readonly ?string $licenseName = null,
6060
protected readonly ?string $licenseUrl = null,
61-
protected readonly ?string $copyrightText = null
61+
protected readonly ?string $copyrightText = null,
62+
protected readonly ?string $caption = null
6263
) {
6364
$this->type = Hyperlinks::isRemote($source) ? self::TYPE_REMOTE : self::TYPE_LOCAL;
6465
$this->source = $this->setSource($source);
@@ -127,6 +128,10 @@ public function getMetadataArray(): array
127128
$metadata['name'] = $this->getTitleText();
128129
}
129130

131+
if ($this->hasCaption()) {
132+
$metadata['caption'] = $this->getCaption();
133+
}
134+
130135
$metadata['url'] = $this->getSource();
131136
$metadata['contentUrl'] = $this->getSource();
132137

@@ -135,7 +140,7 @@ public function getMetadataArray(): array
135140

136141
public function getAltText(): ?string
137142
{
138-
return $this->altText;
143+
return $this->altText ?? $this->caption;
139144
}
140145

141146
public function getTitleText(): ?string
@@ -168,6 +173,11 @@ public function getLicenseUrl(): ?string
168173
return $this->licenseUrl;
169174
}
170175

176+
public function getCaption(): ?string
177+
{
178+
return $this->caption;
179+
}
180+
171181
public function hasAltText(): bool
172182
{
173183
return $this->has('altText');
@@ -203,6 +213,11 @@ public function hasLicenseUrl(): bool
203213
return $this->has('licenseUrl');
204214
}
205215

216+
public function hasCaption(): bool
217+
{
218+
return $this->has('caption');
219+
}
220+
206221
protected function has(string $property): bool
207222
{
208223
return $this->$property !== null;

packages/framework/src/Markdown/Contracts/FrontMatter/SubSchemas/FeaturedImageSchema.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ interface FeaturedImageSchema extends BlogPostSchema
1414
{
1515
public const FEATURED_IMAGE_SCHEMA = [
1616
'source' => 'string', // Name of a file in _media/ or a remote URL (required)
17-
'altText' => 'string', // The alt text (important for accessibility) // todo: Support alt, description
18-
'titleText' => 'string', // The title text (hover tooltip & metadata) // todo: Support title, caption
17+
'altText' => 'string', // The alt text (important for accessibility)
18+
'alt' => 'string', // Alternative to altText (simplified schema)
19+
'titleText' => 'string', // The title text (hover tooltip & metadata)
20+
'caption' => 'string', // The caption text (simplified schema)
1921
'licenseName' => 'string', // The name of the license (e.g. "CC BY 4.0")
2022
'licenseUrl' => 'string', // The URL of the license (e.g. "https://creativecommons.org/licenses/by/4.0/")
2123
'authorName' => 'string', // The name of the author/photographer of the image (e.g. "John Doe", Wikimedia Commons)

packages/framework/tests/Feature/FeaturedImageFactoryTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function testWithDataFromSchema()
4747
'copyrightText' => 'copyright',
4848
'licenseName' => 'license',
4949
'licenseUrl' => 'licenseUrl',
50+
'caption' => null,
5051
];
5152

5253
$factory = new FeaturedImageFactory(new FrontMatter($array));
@@ -146,6 +147,43 @@ public function testImagePathsWithCacheBusting()
146147
$this->assertSourceIsSame('media/foo?v=00000000', ['image' => ['source' => '_media/foo']]);
147148
}
148149

150+
public function testSupportsSimplifiedImageSchema()
151+
{
152+
$array = [
153+
'image' => [
154+
'source' => 'source',
155+
'alt' => 'Alternative text',
156+
'caption' => 'Static website from GitHub Readme',
157+
],
158+
];
159+
160+
$factory = new FeaturedImageFactory(new FrontMatter($array));
161+
$image = FeaturedImageFactory::make(new FrontMatter($array));
162+
163+
$this->assertSame('source', $factory->toArray()['source']);
164+
$this->assertSame('Alternative text', $factory->toArray()['altText']);
165+
$this->assertSame('Static website from GitHub Readme', $factory->toArray()['caption']);
166+
167+
$this->assertSame('Alternative text', $image->getAltText());
168+
$this->assertSame('Static website from GitHub Readme', $image->getCaption());
169+
}
170+
171+
public function testFallsBackToCaptionWhenAltIsMissing()
172+
{
173+
$array = [
174+
'image' => [
175+
'source' => 'source',
176+
'caption' => 'This caption should be used as alt text',
177+
],
178+
];
179+
180+
$image = FeaturedImageFactory::make(new FrontMatter($array));
181+
182+
$this->assertFalse($image->hasAltText());
183+
$this->assertSame('This caption should be used as alt text', $image->getAltText());
184+
$this->assertSame('This caption should be used as alt text', $image->getCaption());
185+
}
186+
149187
protected function makeFromArray(array $matter): FeaturedImage
150188
{
151189
return FeaturedImageFactory::make(new FrontMatter($matter));

packages/framework/tests/Feature/FeaturedImageTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ public function testGetMetadataArray()
4141
'contentUrl' => 'media/source',
4242
], (new FilledImage)->getMetadataArray());
4343

44+
// Test with caption
45+
$this->assertSame([
46+
'text' => 'alt',
47+
'name' => 'title',
48+
'caption' => 'This is a caption',
49+
'url' => 'media/source',
50+
'contentUrl' => 'media/source',
51+
], (new FeaturedImage('source', 'alt', 'title', null, null, null, null, null, 'This is a caption'))->getMetadataArray());
52+
4453
$this->assertSame([
4554
'url' => 'media/source',
4655
'contentUrl' => 'media/source',

packages/framework/tests/Unit/SchemaContractsTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ public function testSchemasAreNotAccidentallyChanged()
6969
$this->assertSame([
7070
'source' => 'string',
7171
'altText' => 'string',
72+
'alt' => 'string',
7273
'titleText' => 'string',
74+
'caption' => 'string',
7375
'licenseName' => 'string',
7476
'licenseUrl' => 'string',
7577
'authorName' => 'string',

packages/framework/tests/Unit/Views/FeaturedImageViewTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,51 @@ public function testImagePathNormalization()
273273
$this->assertStringContainsString('src="custom_media/bar.png"', $component);
274274
}
275275

276+
public function testCaptionIsRenderedWhenPresent()
277+
{
278+
$component = $this->renderComponent([
279+
'image.source' => 'foo.jpg',
280+
'image.caption' => 'This is a caption for the image',
281+
'image.altText' => 'Alt text for the image',
282+
]);
283+
284+
$this->assertStringContainsString('This is a caption for the image', $component);
285+
$this->assertStringContainsString('alt="Alt text for the image"', $component);
286+
}
287+
288+
public function testAltTextFallsBackToCaptionWhenMissing()
289+
{
290+
$component = $this->renderComponent([
291+
'image.source' => 'foo.jpg',
292+
'image.caption' => 'This caption is used as alt text',
293+
]);
294+
295+
$this->assertStringContainsString('This caption is used as alt text', $component);
296+
$this->assertStringContainsString('alt="This caption is used as alt text"', $component);
297+
}
298+
299+
public function testSupportsSimplifiedImageSchema()
300+
{
301+
$this->file('_media/simple.jpg', 'test content');
302+
303+
$image = new FeaturedImage(
304+
'simple.jpg',
305+
null, // altText
306+
null, // titleText
307+
null, // authorName
308+
null, // authorUrl
309+
null, // licenseName
310+
null, // licenseUrl
311+
null, // copyrightText
312+
'Static website from GitHub Readme' // caption
313+
);
314+
315+
$component = $this->renderComponent($image);
316+
317+
$this->assertStringContainsString('Static website from GitHub Readme', $component);
318+
$this->assertStringContainsString('alt="Static website from GitHub Readme"', $component);
319+
}
320+
276321
protected function stripHtml(string $string): string
277322
{
278323
return trim($this->stripWhitespace(strip_tags($string)), "\t ");

0 commit comments

Comments
 (0)