Skip to content

Commit

Permalink
Merge pull request #388 from hydephp/fluent-metadata-handler
Browse files Browse the repository at this point in the history
Unify the $page property and add a fluent metadata helper
  • Loading branch information
caendesilva authored May 17, 2022
2 parents 9612805 + cbc07a9 commit 6aa83b6
Show file tree
Hide file tree
Showing 16 changed files with 290 additions and 67 deletions.
25 changes: 12 additions & 13 deletions config/hyde.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

use Hyde\Framework\Features;
use Hyde\Framework\Meta;

return [

Expand Down Expand Up @@ -70,24 +71,22 @@
| Global Site Meta Tags
|--------------------------------------------------------------------------
|
| While you can add any number of meta tags in the meta.blade.php component,
| these settings allow you to easily add tags for the meta component.
| While you can add any number of meta tags in the meta.blade.php component
| using standard HTML, you can also use the Meta helper. To add a regular
| meta tag, use Meta::name() helper. To add an Open Graph property, use
| Meta::property() helper which also adds the `og:` prefix for you.
|
| The `meta` array is for standard meta tags. See the examples below.
| The `og` array is for Open Graph properties. Do not include the `og:` prefix.
| Please note that these tags might conflict with blog post tags.
|
*/

'meta' => [
// 'author' => 'Mr. Hyde',
// 'twitter:creator' => '@hyde_php',
// 'description' => 'My Hyde Blog',
// 'keywords' => 'Static Sites, Blogs, Documentation',
'generator' => 'HydePHP '.Hyde\Framework\Hyde::version(),
],

'ogProperties' => [
'site_name' => $siteName,
// Meta::name('author', 'Mr. Hyde'),
// Meta::name('twitter:creator', '@hyde_php'),
// Meta::name('description', 'My Hyde Blog'),
// Meta::name('keywords', 'Static Sites, Blogs, Documentation'),
Meta::name('generator', 'HydePHP '.Hyde\Framework\Hyde::version()),
Meta::property('site_name', $siteName),
],

/*
Expand Down
14 changes: 7 additions & 7 deletions resources/views/components/post/article.blade.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<article aria-label="Article" id="{{ Hyde::uriPath() ?? '' }}posts/{{ $post->slug }}" itemscope itemtype="https://schema.org/Article"
<article aria-label="Article" id="{{ Hyde::uriPath() ?? '' }}posts/{{ $page->slug }}" itemscope itemtype="https://schema.org/Article"
@class(['post-article mx-auto prose dark:prose-invert', 'torchlight-enabled' => Hyde\Framework\Features::hasTorchlight()])>
<meta itemprop="identifier" content="{{ $post->slug }}">
<meta itemprop="identifier" content="{{ $page->slug }}">
@if(Hyde::uriPath())
<meta itemprop="url" content="{{ Hyde::uriPath('posts/' . $post->slug) }}">
<meta itemprop="url" content="{{ Hyde::uriPath('posts/' . $page->slug) }}">
@endif

<header aria-label="Header section" role="doc-pageheader">
<h1 itemprop="headline" class="mb-4">{{ $title ?? 'Blog Post' }}</h1>
<div id="byline" aria-label="About the post" role="doc-introduction">
@includeWhen(isset($post->date), 'hyde::components.post.date')
@includeWhen(isset($post->author), 'hyde::components.post.author')
@includeWhen(isset($post->category), 'hyde::components.post.category')
@includeWhen(isset($page->date), 'hyde::components.post.date')
@includeWhen(isset($page->author), 'hyde::components.post.author')
@includeWhen(isset($page->category), 'hyde::components.post.category')
</div>
</header>
@includeWhen(isset($post->image), 'hyde::components.post.image')
@includeWhen(isset($page->image), 'hyde::components.post.image')
<div aria-label="Article body" itemprop="articleBody">
{!! $markdown !!}
</div>
Expand Down
8 changes: 4 additions & 4 deletions resources/views/components/post/author.blade.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
by author
<address itemprop="author" itemscope itemtype="https://schema.org/Person" aria-label="The post author" style="display: inline;">
@if($post->author->website)
<a href="{{ $post->author->website }}" rel="author" itemprop="url" aria-label="The author's website">
@if($page->author->website)
<a href="{{ $page->author->website }}" rel="author" itemprop="url" aria-label="The author's website">
@endif
<span itemprop="name" aria-label="The author's name" {{ ($post->author->username && ($post->author->username !== $post->author->name)) ? 'title=@'. urlencode($post->author->username) .'' : '' }}>{{ $post->author->name ?? $post->author->username }}</span>
@if($post->author->website)
<span itemprop="name" aria-label="The author's name" {{ ($page->author->username && ($page->author->username !== $page->author->name)) ? 'title=@'. urlencode($page->author->username) .'' : '' }}>{{ $page->author->name ?? $page->author->username }}</span>
@if($page->author->website)
</a>
@endif
</address>
2 changes: 1 addition & 1 deletion resources/views/components/post/category.blade.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
in the category "{{ $post->category }}"
in the category "{{ $page->category }}"
2 changes: 1 addition & 1 deletion resources/views/components/post/date.blade.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Posted <time itemprop="dateCreated datePublished" datetime="{{ $post->date->datetime }}" title="{{ $post->date->sentence }}">{{ $post->date->short }}</time>
Posted <time itemprop="dateCreated datePublished" datetime="{{ $page->date->datetime }}" title="{{ $page->date->sentence }}">{{ $page->date->short }}</time>
2 changes: 1 addition & 1 deletion resources/views/components/post/description.blade.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<p itemprop="abstract">
{{ $post->matter['description'] }}
{{ $page->matter['description'] }}
</p>
6 changes: 3 additions & 3 deletions resources/views/components/post/image.blade.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<figure aria-label="Cover image" role="doc-cover" itemprop="image" itemscope itemtype="https://schema.org/ImageObject">
<img src="{{ $post->image->getSource() }}" alt="{{ $post->image->description ?? '' }}" title="{{ $post->image->title ?? '' }}" itemprop="image" class="mb-0">
<img src="{{ $page->image->getSource() }}" alt="{{ $page->image->description ?? '' }}" title="{{ $page->image->title ?? '' }}" itemprop="image" class="mb-0">
<figcaption aria-label="Image caption" itemprop="caption">
{!! $post->image->getFluentAttribution() !!}
{!! $page->image->getFluentAttribution() !!}
</figcaption>
@foreach ($post->image->getMetadataArray() as $name => $value)
@foreach ($page->image->getMetadataArray() as $name => $value)
<meta itemprop="{{ $name }}" content="{{ $value }}">
@endforeach
</figure>
9 changes: 1 addition & 8 deletions resources/views/layouts/meta.blade.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
{{-- Config Defined Meta Tags --}}
@foreach (config('hyde.meta', []) as $name => $content)
<meta name="{{ $name }}" content="{{ $content }}">
@endforeach

@foreach (config('hyde.ogProperties', []) as $property => $content)
<meta property="og:{{ $property }}" content="{{ $content }}">
@endforeach
{!! Hyde\Framework\Meta::render() !!}

{{-- Add any extra tags to include in the <head> section --}}
@stack('meta')

4 changes: 2 additions & 2 deletions resources/views/layouts/post.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

@push('meta')
<!-- Blog Post Meta Tags -->
@foreach ($post->getMetadata() as $name => $content)
@foreach ($page->getMetadata() as $name => $content)
<meta name="{{ $name }}" content="{{ $content }}">
@endforeach
@foreach ($post->getMetaProperties() as $name => $content)
@foreach ($page->getMetaProperties() as $name => $content)
<meta property="{{ $name }}" content="{{ $content }}">
@endforeach
@endpush
Expand Down
39 changes: 16 additions & 23 deletions src/Concerns/HasMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Hyde\Framework\Hyde;
use Hyde\Framework\Models\Metadata;
use Hyde\Framework\Services\AuthorService;
use JetBrains\PhpStorm\ArrayShape;

/**
Expand All @@ -12,6 +13,9 @@
*
* @see \Hyde\Framework\Models\Metadata
* @see \Tests\Feature\Concerns\HasMetadataTest
*
* @todo Unify the $page property and handle metadata through it
* @todo Only add blog post properties if the page is a blog post
*/
trait HasMetadata
{
Expand All @@ -25,14 +29,14 @@ public function constructMetadata(): void
}

#[ArrayShape(['name' => "\content"])]
public function getMetadata(): array
{
if (! isset($this->metadata)) {
return [];
}
public function getMetadata(): array
{
if (! isset($this->metadata)) {
return [];
}

return $this->metadata->metadata;
}
return $this->metadata->metadata;
}

#[ArrayShape(['property' => 'content'])]
public function getMetaProperties(): array
Expand All @@ -46,6 +50,8 @@ public function getMetaProperties(): array

/**
* Generate metadata from the front matter that can be used in standard <meta> tags.
*
* @deprecated Will be refactored to parseFrontMatterMetadata
*/
protected function makeMetadata(): void
{
Expand All @@ -54,7 +60,7 @@ protected function makeMetadata(): void
}

if (isset($this->matter['author'])) {
$this->metadata->add('author', $this->getAuthor($this->matter['author']));
$this->metadata->add('author', AuthorService::getAuthorName($this->matter['author']));
}

if (isset($this->matter['category'])) {
Expand All @@ -65,6 +71,8 @@ protected function makeMetadata(): void
/**
* Generate metadata from the front matter that can be used for og:type <meta> tags.
* Note that this currently assumes that the object using it is a Blog Post.
*
* @deprecated Will be refactored to parseFrontMatterMetadata
*/
protected function makeMetaProperties(): void
{
Expand Down Expand Up @@ -96,19 +104,4 @@ protected function makeMetaProperties(): void
}
}
}

/**
* Parse the author string from the front matter with support for both flat and array notation.
*
* @param string|array $author
* @return string
*/
protected function getAuthor(string|array $author): string
{
if (is_string($author)) {
return $author;
}

return $author['username'] ?? $author['name'] ?? 'Guest';
}
}
62 changes: 62 additions & 0 deletions src/Meta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Hyde\Framework;

/**
* Helpers to fluently declare HTML meta tags.
*
* @see \Tests\Feature\MetadataHelperTest
*/
class Meta
{
public static function name(string $name, string $content): string
{
return '<meta name="'.e($name).'" content="'.e($content).'">';
}

public static function property(string $property, string $content): string
{
$property = static::formatOpenGraphProperty($property);

return '<meta property="'.e($property).'" content="'.e($content).'">';
}

public static function render(array $overridesGlobalMeta = []): string
{
return implode("\n",
static::filterUnique(
array_merge(
static::getGlobalMeta(),
$overridesGlobalMeta
)
)
);
}

protected static function filterUnique(array $meta): array
{
$array = [];
$existing = [];

foreach ($meta as $metaItem) {
$substring = substr($metaItem, 6, strpos($metaItem, ' content="') - 6);

if (! in_array($substring, $existing)) {
$array[] = $metaItem;
$existing[] = $substring;
}
}

return $array;
}

public static function getGlobalMeta(): array
{
return config('hyde.meta', []);
}

protected static function formatOpenGraphProperty(string $property): string
{
return str_starts_with($property, 'og:') ? $property : 'og:'.$property;
}
}
2 changes: 2 additions & 0 deletions src/Models/Metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
/**
* Metadata class for storing metadata about a model.
* Is used in Blade views to create <meta> tags.
*
* @deprecated Will be merged with Meta class
*/
class Metadata
{
Expand Down
15 changes: 15 additions & 0 deletions src/Services/AuthorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,19 @@ public static function find(string $username, bool $forgiving = true): Author|fa

return $service->authors->firstWhere('username', $username) ?? false;
}

/**
* Parse the author name string from front matter with support for both flat and array notation.
*
* @param string|array $author
* @return string
*/
public static function getAuthorName(string|array $author): string
{
if (is_string($author)) {
return $author;
}

return $author['name'] ?? $author['username'] ?? 'Guest';
}
}
8 changes: 4 additions & 4 deletions src/StaticPageBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ class StaticPageBuilder
*/
public function __construct(protected MarkdownDocument|BladePage $page, bool $selfInvoke = false)
{
$this->needsDirectory(static::$outputPath);

if ($selfInvoke) {
$this->__invoke();
}

$this->needsDirectory(static::$outputPath);
}

/**
Expand All @@ -44,6 +44,8 @@ public function __construct(protected MarkdownDocument|BladePage $page, bool $se
*/
public function __invoke()
{
view()->share('page', $this->page);

if ($this->page instanceof BladePage) {
return $this->save($this->page->view, $this->compileView());
}
Expand Down Expand Up @@ -98,7 +100,6 @@ private function compileView(): string
private function compilePost(): string
{
return view('hyde::layouts/post')->with([
'post' => $this->page,
'title' => $this->page->title,
'markdown' => MarkdownConverter::parse($this->page->body),
'currentPage' => 'posts/'.$this->page->slug,
Expand Down Expand Up @@ -127,7 +128,6 @@ private function compilePage(): string
private function compileDocs(): string
{
return view('hyde::layouts/docs')->with([
'docs' => $this->page,
'title' => $this->page->title,
'markdown' => MarkdownConverter::parse($this->page->body, DocumentationPage::class),
'currentPage' => Hyde::docsDirectory().'/'.$this->page->slug,
Expand Down
17 changes: 17 additions & 0 deletions tests/Feature/AuthorServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,21 @@ public function test_get_yaml_method_returns_empty_array_if_file_does_not_contai

$this->assertEquals([], $service->getYaml());
}

public function test_get_author_name_helper_returns_string_for_string()
{
$this->assertEquals('foo', AuthorService::getAuthorName('foo'));
}

public function test_get_author_name_helper_returns_string_for_array()
{
$this->assertEquals('foo', AuthorService::getAuthorName(['name' => 'foo']));
}

public function test_get_author_name_helper_returns_string_for_array_with_proper_fallback_priorities()
{
$this->assertEquals('foo', AuthorService::getAuthorName(['name' => 'foo', 'username' => 'bar']));
$this->assertEquals('bar', AuthorService::getAuthorName(['username' => 'bar']));
$this->assertEquals('Guest', AuthorService::getAuthorName([]));
}
}
Loading

0 comments on commit 6aa83b6

Please sign in to comment.