Skip to content

Commit 97d4b5b

Browse files
authored
Merge pull request #2175 from hydephp/simplified-front-matter-image-schema
[2.x] Simplified front matter image schema
2 parents 4afcbf6 + 6de0493 commit 97d4b5b

File tree

11 files changed

+230
-29
lines changed

11 files changed

+230
-29
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ This serves two purposes:
3939
- Added Vite facade in https://github.com/hydephp/develop/pull/2016
4040
- Added a custom Blade-based heading renderer for Markdown conversions in https://github.com/hydephp/develop/pull/2047
4141
- The `publish:views` command is now interactive for Unix-like systems in https://github.com/hydephp/develop/pull/2062
42+
- Added a new simplified blog post image front matter schema using a new "caption" field in https://github.com/hydephp/develop/pull/2175
4243

4344
### Changed
4445

docs/creating-content/blog-posts.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ The image source will be used as-is, and no additional processing is done.
212212
image: https://cdn.example.com/image.jpg
213213
```
214214

215-
#### Data-rich image
215+
#### Data-rich image and captions
216216

217217
You can also supply an array of data to construct a rich image with a fluent caption.
218218

@@ -226,9 +226,20 @@ image:
226226
licenseUrl: https://example.com/license/
227227
authorUrl: https://photographer.example.com/
228228
authorName: "John Doe"
229+
caption: "Overrides the fluent caption feature"
229230
```
230231

231-
>info See [posts/introducing-images](https://hydephp.com/posts/introducing-images) for a detailed blog post with examples and schema information!
232+
The data will then be used for metadata and to render a fluently worded caption. If you just want to add a quick caption, you can instead simply set the "caption field" to override the caption; or if you simply want a caption and no metadata this is a quick option as well.
233+
```yaml
234+
image:
235+
source: how-to-turn-your-github-readme-into-a-static-website-cropped.png
236+
alt: Example of a static website created from a GitHub Readme
237+
caption: Static website from GitHub Readme with **Markdown** support!
238+
```
239+
240+
The caption field supports inline Markdown formatting like **bold**, *italic*, and [links](https://example.com). This makes it easy to add rich text formatting to your image captions.
241+
242+
If the `alt` field is missing, the caption will be used as the alt text as well.
232243

233244
## Using Images in Posts
234245

docs/creating-content/managing-assets.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,4 @@ To improve accessibility, you should always add an `alt` text. Here is a full ex
183183

184184
Hyde offers great support for creating data-rich and accessible featured images for blog posts.
185185

186-
You can read more about this on the [creating blog posts page](blog-posts#image).
186+
You can read more about this on the [creating blog posts page](blog-posts#data-rich-image-and-captions).

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

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,39 @@
22
/** @var \Hyde\Pages\MarkdownPost $page */
33
/** @var \Hyde\Framework\Features\Blogging\Models\FeaturedImage $image */
44
$image = $page->image;
5+
6+
use Illuminate\Support\Str;
57
@endphp
68
<figure aria-label="Cover image" itemprop="image" itemscope itemtype="https://schema.org/ImageObject" role="doc-cover">
79
<img src="{{ $image->getSource() }}" alt="{{ $image->getAltText() ?? '' }}" title="{{ $image->getTitleText() ?? '' }}" itemprop="image" class="mb-0">
810
<figcaption aria-label="Image caption" itemprop="caption">
9-
@if($image->hasAuthorName())
10-
<span>Image by</span>
11-
<span itemprop="creator" itemscope="" itemtype="https://schema.org/Person">
12-
@if($image->hasAuthorUrl())
13-
<a href="{{ $image->getAuthorUrl() }}" rel="author noopener nofollow" itemprop="url">
11+
@if($image->hasCaption())
12+
<span>{!! Str::inlineMarkdown($image->getCaption()) !!}</span>
13+
@else
14+
@if($image->hasAuthorName())
15+
<span>Image by</span>
16+
<span itemprop="creator" itemscope="" itemtype="https://schema.org/Person">
17+
@if($image->hasAuthorUrl())
18+
<a href="{{ $image->getAuthorUrl() }}" rel="author noopener nofollow" itemprop="url">
19+
<span itemprop="name">{{ $image->getAuthorName() }}</span>.
20+
</a>
21+
@else
1422
<span itemprop="name">{{ $image->getAuthorName() }}</span>.
15-
</a>
16-
@else
17-
<span itemprop="name">{{ $image->getAuthorName() }}</span>.
18-
@endif
19-
</span>
20-
@endif
23+
@endif
24+
</span>
25+
@endif
2126

22-
@if($image->hasCopyrightText())
23-
<span itemprop="copyrightNotice">{{ $image->getCopyrightText() }}</span>.
24-
@endif
27+
@if($image->hasCopyrightText())
28+
<span itemprop="copyrightNotice">{{ $image->getCopyrightText() }}</span>.
29+
@endif
2530

26-
@if($image->hasLicenseName())
27-
<span>License</span>
28-
@if($image->hasLicenseUrl())
29-
<a href="{{ $image->getLicenseUrl() }}" rel="license nofollow noopener" itemprop="license">{{ $image->getLicenseName() }}</a>.
30-
@else
31-
<span itemprop="license">{{ $image->getLicenseName() }}</span>.
31+
@if($image->hasLicenseName())
32+
<span>License</span>
33+
@if($image->hasLicenseUrl())
34+
<a href="{{ $image->getLicenseUrl() }}" rel="license nofollow noopener" itemprop="license">{{ $image->getLicenseName() }}</a>.
35+
@else
36+
<span itemprop="license">{{ $image->getLicenseName() }}</span>.
37+
@endif
3238
@endif
3339
@endif
3440
</figcaption>

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',

0 commit comments

Comments
 (0)