Skip to content

Commit

Permalink
Merge pull request #367 from hydephp/store-metadata-in-page-object
Browse files Browse the repository at this point in the history
Refactor metadata system
  • Loading branch information
caendesilva authored Aug 8, 2022
2 parents 80ddec4 + 0ad3391 commit cae974b
Show file tree
Hide file tree
Showing 20 changed files with 1,078 additions and 479 deletions.
12 changes: 10 additions & 2 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ The way metadata tags are handled internally is also refactored. The rendered re
- Adds new actions to handle complex dynamic constructors
- Adds new front matter schema traits to define the public API for front matter and hold their data
- Adds new Meta::link() helper to create `<link>` tags
- Adds new Meta::get() helper to get the metadata array
- Adds a new system for creating and storing page metadata
- Adds several new metadata model classes

### Changed
- Breaking: Rename AbstractMarkdownPage constructor parameter `slug` to `identifier`
Expand All @@ -23,7 +26,9 @@ The way metadata tags are handled internally is also refactored. The rendered re
- Major: Restructure internal page data to use new front matter schema traits
- Begin changing references to slugs to identifiers, see motivation below
- Makes some helpers in SourceFileParser public static allowing them to be used outside the class
- The Image model and featured blog post image helpers now consistently use image paths relative to the `_media` directory as is described in the documentation
- Page metadata is now stored as a page property, making it easier to see and understand
- Page metadata is now generated at compile time instead of build time
- Page metadata types are now strongly typed, however all types are String able, so end usage is not affected

### Deprecated
- Deprecated `Facades\Markdown::parse()`, use `Facades\Markdown::render()` instead
Expand All @@ -34,10 +39,13 @@ The way metadata tags are handled internally is also refactored. The rendered re
- Removed `body()` method from `MarkdownDocumentContract` interface and all its implementations. Use `markdown()->body()` (or cast to string) instead
- Removed `body` property from Markdown pages. Use `markdown()->body()` (or cast to string) instead
- Removed deprecated `Helpers\Author` (fully merged into `Models\Author`, simply swap namespace to upgrade)
- Removed metadata constructor helpers from the MarkdownPost class as it is now handled in the new metadata class
- Several internal single-use helper traits have been merged into their respective classes

### Fixed
- for any bug fixes.
- Fix Path property in Image model should be relative to media directory [#359](https://github.com/hydephp/develop/issues/359)
- Fix Add toString method to Image model to get the link [#370](https://github.com/hydephp/develop/issues/370)
- Fix Blog post OpenGraph images must be resolved relatively [#374](https://github.com/hydephp/develop/issues/374)

### Security
- in case of vulnerabilities.
Expand Down
77 changes: 26 additions & 51 deletions packages/framework/src/Contracts/AbstractPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@

use Hyde\Framework\Actions\SourceFileParser;
use Hyde\Framework\Concerns\FrontMatter\Schemas\PageSchema;
use Hyde\Framework\Helpers\Meta;
use Hyde\Framework\Hyde;
use Hyde\Framework\Models\FrontMatter;
use Hyde\Framework\Models\Pages\MarkdownPost;
use Hyde\Framework\Models\Metadata\Metadata;
use Hyde\Framework\Models\Route;
use Hyde\Framework\Services\DiscoveryService;
use Illuminate\Support\Collection;
Expand All @@ -34,6 +32,20 @@ abstract class AbstractPage implements PageContract, CompilableContract

public string $identifier;
public FrontMatter $matter;
public Metadata $metadata;

public function __construct(string $identifier = '', FrontMatter|array $matter = [])
{
$this->identifier = $identifier;
$this->matter = $matter instanceof FrontMatter ? $matter : new FrontMatter($matter);
$this->constructPageSchemas();
$this->metadata = new Metadata($this);
}

protected function constructPageSchemas(): void
{
$this->constructPageSchema();
}

/** @inheritDoc */
final public static function getSourceDirectory(): string
Expand Down Expand Up @@ -93,18 +105,6 @@ public static function getOutputLocation(string $basename): string
).'.html';
}

public function __construct(string $identifier = '', FrontMatter|array $matter = [])
{
$this->identifier = $identifier;
$this->matter = $matter instanceof FrontMatter ? $matter : new FrontMatter($matter);
$this->constructPageSchemas();
}

protected function constructPageSchemas(): void
{
$this->constructPageSchema();
}

/** @inheritDoc */
public function get(string $key = null, mixed $default = null): mixed
{
Expand All @@ -121,6 +121,16 @@ public function matter(string $key = null, mixed $default = null): mixed
return $this->matter->get($key, $default);
}

/** @inheritDoc */
public function has(string $key, bool $strict = false): bool
{
if ($strict) {
return property_exists($this, $key) || $this->matter->has($key);
}

return ! blank($this->get($key));
}

/** @inheritDoc */
public function getIdentifier(): string
{
Expand Down Expand Up @@ -166,44 +176,9 @@ public function getBladeView(): string
/** @inheritDoc */
abstract public function compile(): string;

/**
* @internal
*
* @return string[]
*
* @psalm-return list<string>
*/
public function getDynamicMetadata(): array
{
$array = [];

if (! empty($this->canonicalUrl)) {
$array[] = Meta::link('canonical', $this->canonicalUrl);
}

if (! empty($this->title)) {
$array[] = Meta::name('twitter:title', $this->htmlTitle());
$array[] = Meta::property('title', $this->htmlTitle());
}

if ($this instanceof MarkdownPost) {
$array[] = "\n<!-- Blog Post Meta Tags -->";
foreach ($this->getMetadata() as $name => $content) {
$array[] = Meta::name($name, $content);
}
foreach ($this->getMetaProperties() as $property => $content) {
$array[] = Meta::property($property, $content);
}
}

return $array;
}

public function renderPageMetadata(): string
{
return Meta::render(
withMergedData: $this->getDynamicMetadata()
);
return $this->metadata->render();
}

public function showInNavigation(): bool
Expand Down
10 changes: 10 additions & 0 deletions packages/framework/src/Contracts/MetadataItemContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Hyde\Framework\Contracts;

interface MetadataItemContract
{
public function __toString(): string;

public function uniqueKey(): string;
}
9 changes: 9 additions & 0 deletions packages/framework/src/Contracts/PageContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ public function get(string $key = null, mixed $default = null): mixed;
*/
public function matter(string $key = null, mixed $default = null): mixed;

/**
* See if a value exists in the computed page data or the front matter.
*
* @param string $key
* @param bool $strict When set to true, an additional check if the property is not blank is performed.
* @return bool
*/
public function has(string $key, bool $strict = false): bool;

/**
* Get the directory in where source files are stored.
*
Expand Down
59 changes: 19 additions & 40 deletions packages/framework/src/Helpers/Meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace Hyde\Framework\Helpers;

use Hyde\Framework\Hyde;
use Hyde\Framework\Services\RssFeedService;
use Hyde\Framework\Models\Metadata\LinkItem;
use Hyde\Framework\Models\Metadata\MetadataItem;
use Hyde\Framework\Models\Metadata\OpenGraphItem;

/**
* Helpers to fluently declare HTML meta tags.
Expand All @@ -12,41 +13,36 @@
*/
class Meta
{
public static function name(string $name, string $content): string
public static function name(string $name, string $content): MetadataItem
{
return '<meta name="'.e($name).'" content="'.e($content).'">';
return new MetadataItem($name, $content);
}

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

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

public static function link(string $rel, string $href, array $attr = []): string
public static function link(string $rel, string $href, array $attr = []): LinkItem
{
if (! $attr) {
return '<link rel="'.e($rel).'" href="'.e($href).'">';
}

$attributes = collect($attr)->map(function ($value, $key) {
return e($key).'="'.e($value).'"';
})->implode(' ');
return new LinkItem($rel, $href, $attr);
}

return '<link rel="'.e($rel).'" href="'.e($href).'" '.$attributes.'>';
public static function get(array $withMergedData = []): array
{
return static::filterUnique(
array_merge(
static::getGlobalMeta(),
$withMergedData
)
);
}

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

Expand Down Expand Up @@ -79,28 +75,11 @@ protected static function getDynamicMeta(): array
{
$array = [];

if (Features::sitemap()) {
$array[] = Meta::link('sitemap', Hyde::url('sitemap.xml'), [
'type' => 'application/xml', 'title' => 'Sitemap',
]);
}

if (Features::rss()) {
$array[] = Meta::link('alternate', Hyde::url(RssFeedService::getDefaultOutputFilename()), [
'type' => 'application/rss+xml', 'title' => RssFeedService::getDescription(),
]);
}

return $array;
}

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

protected static function formatOpenGraphProperty(string $property): string
{
return str_starts_with($property, 'og:') ? $property : 'og:'.$property;
}
}
5 changes: 5 additions & 0 deletions packages/framework/src/Models/FrontMatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public function set(string $key, mixed $value): static
return $this;
}

public function has(string $key): bool
{
return Arr::has($this->data, $key);
}

public function toArray(): array
{
return $this->data;
Expand Down
30 changes: 30 additions & 0 deletions packages/framework/src/Models/Metadata/LinkItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Hyde\Framework\Models\Metadata;

use Hyde\Framework\Contracts\MetadataItemContract;

class LinkItem implements MetadataItemContract, \Stringable
{
public function __construct(protected string $rel, protected string $href, protected array $attr = [])
{
}

public function __toString(): string
{
if (! $this->attr) {
return '<link rel="'.e($this->rel).'" href="'.e($this->href).'">';
}

$attributes = collect($this->attr)->map(function ($value, $key) {
return e($key).'="'.e($value).'"';
})->implode(' ');

return '<link rel="'.e($this->rel).'" href="'.e($this->href).'" '.$attributes.'>';
}

public function uniqueKey(): string
{
return $this->rel;
}
}
Loading

0 comments on commit cae974b

Please sign in to comment.