From 8ef74777a09204aaef99cd0f304953eb5318dd6a Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Sun, 3 May 2020 14:15:39 +0200 Subject: [PATCH 1/3] Improve `title_format` and add `excerpt_format` attributes in ContentTypes --- config/bolt/contenttypes.yaml | 3 +- .../Parser/ContentTypesParser.php | 2 +- src/Twig/ContentExtension.php | 64 +++++----------- src/Utils/ComposeValueHelper.php | 75 +++++++++++++++++++ 4 files changed, 97 insertions(+), 47 deletions(-) diff --git a/config/bolt/contenttypes.yaml b/config/bolt/contenttypes.yaml index b384ed487..a4db55552 100644 --- a/config/bolt/contenttypes.yaml +++ b/config/bolt/contenttypes.yaml @@ -58,7 +58,8 @@ homepage: pages: name: Pages singular_name: Page - title_format: [ heading, subheading ] + title_format: '🍃 {heading} - {subheading} *' + excerpt_format: '👑 {heading} - {subheading} *' fields: heading: type: text diff --git a/src/Configuration/Parser/ContentTypesParser.php b/src/Configuration/Parser/ContentTypesParser.php index f58de6cc6..b1053ffe0 100644 --- a/src/Configuration/Parser/ContentTypesParser.php +++ b/src/Configuration/Parser/ContentTypesParser.php @@ -178,7 +178,7 @@ protected function parseContentType($key, array $contentType): ?ContentType // Make sure title_format is set if (isset($contentType['title_format'])) { - $contentType['title_format'] = (array) $contentType['title_format']; + $contentType['title_format'] = $contentType['title_format']; } elseif (isset($contentType['fields']['slug']['uses'])) { $contentType['title_format'] = (array) $contentType['fields']['slug']['uses']; } else { diff --git a/src/Twig/ContentExtension.php b/src/Twig/ContentExtension.php index bf970bb18..62dcec2ec 100644 --- a/src/Twig/ContentExtension.php +++ b/src/Twig/ContentExtension.php @@ -102,7 +102,7 @@ public function getFilters(): array return [ new TwigFilter('title', [$this, 'getTitle'], $safe), - new TwigFilter('title_fields', [$this, 'guessTitleFields']), + new TwigFilter('title_fields', [$this, 'TitleFields']), new TwigFilter('image', [$this, 'getImage']), new TwigFilter('excerpt', [$this, 'getExcerpt'], $safe), new TwigFilter('previous', [$this, 'getPreviousContent']), @@ -165,10 +165,21 @@ public function getAnyTitle(Content $content, int $length = 120): string } public function getTitle(Content $content, string $locale = '', int $length = 120): string + { + if (ComposeValueHelper::isSuitable($content)) { + $title = ComposeValueHelper::get($content, $content->getDefinition()->get('title_format')); + } else { + $title = $this->getFieldBasedTitle($content); + } + + return Html::trimText($title, $length); + } + + private function getFieldBasedTitle(Content $content): string { $titleParts = []; - foreach ($this->guessTitleFields($content) as $fieldName) { + foreach (ComposeValueHelper::guessTitleFields($content) as $fieldName) { $field = $content->getField($fieldName); if (! empty($locale)) { @@ -184,53 +195,16 @@ public function getTitle(Content $content, string $locale = '', int $length = 12 $titleParts[] = $value; } - return Html::trimText(implode(' ', $titleParts), $length); + return implode(' ', $titleParts); } - public function guessTitleFields(Content $content): array + public function getTitleFields(Content $content): array { - $definition = $content->getDefinition(); - - // First, see if we have a "title format" in the Content Type. - if ($definition !== null && $definition->has('title_format')) { - $names = $definition->get('title_format'); - - $namesCollection = Collection::wrap($names)->filter(function (string $name) use ($content): bool { - if ($content->hasFieldDefined($name) === false) { - throw new \RuntimeException(sprintf( - "Content '%s' has field '%s' added to title_format config option, but the field is not present in Content's definition.", - $content->getContentTypeName(), - $name - )); - } - - return $content->hasField($name); - }); - - if ($namesCollection->isNotEmpty()) { - return $namesCollection->values()->toArray(); - } - } - - // Alternatively, see if we have a field named 'title' or somesuch. - $names = ['title', 'name', 'caption', 'subject']; // English - $names = array_merge($names, ['titel', 'naam', 'kop', 'onderwerp']); // Dutch - $names = array_merge($names, ['nom', 'sujet']); // French - $names = array_merge($names, ['nombre', 'sujeto']); // Spanish - - foreach ($names as $name) { - if ($content->hasField($name)) { - return (array) $name; - } - } - - foreach ($content->getFields() as $field) { - if ($field instanceof Excerptable) { - return (array) $field->getName(); - } + if (ComposeValueHelper::isSuitable($content)) { + return ComposeValueHelper::getFieldNames($content->getDefinition()->get('title_format')); } - return []; + return ComposeValueHelper::guessTitleFields($content); } /** @@ -279,7 +253,7 @@ public function getExcerpt($content, int $length = 280, bool $includeTitle = fal } } - $skipFields = $this->guessTitleFields($content); + $skipFields = ComposeValueHelper::guessTitleFields($content); foreach ($content->getFields() as $field) { if ($field instanceof Excerptable && in_array($field->getName(), $skipFields, true) === false) { diff --git a/src/Utils/ComposeValueHelper.php b/src/Utils/ComposeValueHelper.php index 0f0f7ce1e..f860e2697 100644 --- a/src/Utils/ComposeValueHelper.php +++ b/src/Utils/ComposeValueHelper.php @@ -5,9 +5,25 @@ namespace Bolt\Utils; use Bolt\Entity\Content; +use Bolt\Entity\Field\Excerptable; +use Tightenco\Collect\Support\Collection; class ComposeValueHelper { + public static function isSuitable(Content $record): bool + { + $definition = $record->getDefinition(); + + if ($definition !== null && $definition->has('title_format')) { + $format = $definition->get('title_format'); + if (is_string($format) && strpos($format, '{') !== false) { + return true; + } + } + + return false; + } + public static function get(Content $record, string $format = '', string $locale = ''): string { if (empty($format)) { @@ -48,4 +64,63 @@ function ($match) use ($record, $locale) { $format ); } + + public static function getFieldNames(string $format): array + { + $res = preg_match_all('/{([\w]+)}/i', $format, $matches); + + dump($matches[1]); + return $matches[1]; + } + + + public static function guessTitleFields(Content $content): array + { + $definition = $content->getDefinition(); + + // First, see if we have a "title format" in the Content Type. + if ($definition !== null && $definition->has('title_format')) { + + if (ComposeValueHelper::isSuitable($content)) { + $names = ComposeValueHelper::getFieldNames($definition->get('title_format')); + } else { + $names = $definition->get('title_format'); + } + + $namesCollection = Collection::wrap($names)->filter(function (string $name) use ($content): bool { + if ($content->hasFieldDefined($name) === false) { + throw new \RuntimeException(sprintf( + "Content '%s' has field '%s' added to title_format config option, but the field is not present in Content's definition.", + $content->getContentTypeName(), + $name + )); + } + return $content->hasField($name); + }); + + if ($namesCollection->isNotEmpty()) { + return $namesCollection->values()->toArray(); + } + } + + // Alternatively, see if we have a field named 'title' or somesuch. + $names = ['title', 'name', 'caption', 'subject']; // English + $names = array_merge($names, ['titel', 'naam', 'kop', 'onderwerp']); // Dutch + $names = array_merge($names, ['nom', 'sujet']); // French + $names = array_merge($names, ['nombre', 'sujeto']); // Spanish + + foreach ($names as $name) { + if ($content->hasField($name)) { + return (array) $name; + } + } + + foreach ($content->getFields() as $field) { + if ($field instanceof Excerptable) { + return (array) $field->getName(); + } + } + + return []; + } } From ceb83b1dbdc712ec407690b40ec521d3173e2a81 Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Sun, 3 May 2020 15:56:23 +0200 Subject: [PATCH 2/3] Allow `excerpt_format` --- src/Twig/ContentExtension.php | 13 ++++++++++++- src/Utils/ComposeValueHelper.php | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Twig/ContentExtension.php b/src/Twig/ContentExtension.php index 62dcec2ec..8032c26ca 100644 --- a/src/Twig/ContentExtension.php +++ b/src/Twig/ContentExtension.php @@ -242,6 +242,17 @@ public function getExcerpt($content, int $length = 280, bool $includeTitle = fal return Excerpt::getExcerpt((string) $content, $length); } + if (ComposeValueHelper::isSuitable($content, 'excerpt_format')) { + $excerpt = ComposeValueHelper::get($content, $content->getDefinition()->get('excerpt_format')); + } else { + $excerpt = $this->getFieldBasedExcerpt($content, $includeTitle); + } + + return Excerpt::getExcerpt(rtrim($excerpt, '. '), $length, $focus); + } + + private function getFieldBasedExcerpt(Content $content, bool $includeTitle = false): string + { $excerptParts = []; if ($includeTitle) { @@ -274,7 +285,7 @@ public function getExcerpt($content, int $length = 280, bool $includeTitle = fal return $excerpt . $part . ' '; }, ''); - return Excerpt::getExcerpt(rtrim($excerpt, '. '), $length, $focus); + return rtrim($excerpt, '. '); } public function getPreviousContent(Content $content, string $byColumn = 'id', bool $sameContentType = true): ?Content diff --git a/src/Utils/ComposeValueHelper.php b/src/Utils/ComposeValueHelper.php index f860e2697..a71985676 100644 --- a/src/Utils/ComposeValueHelper.php +++ b/src/Utils/ComposeValueHelper.php @@ -10,12 +10,12 @@ class ComposeValueHelper { - public static function isSuitable(Content $record): bool + public static function isSuitable(Content $record, string $which = 'title_format'): bool { $definition = $record->getDefinition(); - if ($definition !== null && $definition->has('title_format')) { - $format = $definition->get('title_format'); + if ($definition !== null && $definition->has($which)) { + $format = $definition->get($which); if (is_string($format) && strpos($format, '{') !== false) { return true; } From 606103e413a44565d308a74443d97230940ae683 Mon Sep 17 00:00:00 2001 From: Bob den Otter Date: Sun, 3 May 2020 16:16:09 +0200 Subject: [PATCH 3/3] Tweak, tweak --- config/bolt/contenttypes.yaml | 4 ++-- src/Twig/ContentExtension.php | 9 ++++----- src/Utils/ComposeValueHelper.php | 12 +++++------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/config/bolt/contenttypes.yaml b/config/bolt/contenttypes.yaml index a4db55552..4bd7a5caf 100644 --- a/config/bolt/contenttypes.yaml +++ b/config/bolt/contenttypes.yaml @@ -58,8 +58,8 @@ homepage: pages: name: Pages singular_name: Page - title_format: '🍃 {heading} - {subheading} *' - excerpt_format: '👑 {heading} - {subheading} *' + title_format: '{heading} - {subheading}' + excerpt_format: '📦 {teaser}' fields: heading: type: text diff --git a/src/Twig/ContentExtension.php b/src/Twig/ContentExtension.php index 8032c26ca..8648a0991 100644 --- a/src/Twig/ContentExtension.php +++ b/src/Twig/ContentExtension.php @@ -102,7 +102,7 @@ public function getFilters(): array return [ new TwigFilter('title', [$this, 'getTitle'], $safe), - new TwigFilter('title_fields', [$this, 'TitleFields']), + new TwigFilter('title_fields', [$this, 'getTitleFields']), new TwigFilter('image', [$this, 'getImage']), new TwigFilter('excerpt', [$this, 'getExcerpt'], $safe), new TwigFilter('previous', [$this, 'getPreviousContent']), @@ -245,13 +245,13 @@ public function getExcerpt($content, int $length = 280, bool $includeTitle = fal if (ComposeValueHelper::isSuitable($content, 'excerpt_format')) { $excerpt = ComposeValueHelper::get($content, $content->getDefinition()->get('excerpt_format')); } else { - $excerpt = $this->getFieldBasedExcerpt($content, $includeTitle); + $excerpt = $this->getFieldBasedExcerpt($content, $length, $includeTitle); } return Excerpt::getExcerpt(rtrim($excerpt, '. '), $length, $focus); } - private function getFieldBasedExcerpt(Content $content, bool $includeTitle = false): string + private function getFieldBasedExcerpt(Content $content, int $length, bool $includeTitle = false): string { $excerptParts = []; @@ -259,7 +259,6 @@ private function getFieldBasedExcerpt(Content $content, bool $includeTitle = fal $title = $this->getTitle($content); if ($title !== '') { $title = Html::trimText($title, $length); - $length -= mb_strlen($title); $excerptParts[] = $title; } } @@ -278,7 +277,7 @@ private function getFieldBasedExcerpt(Content $content, bool $includeTitle = fal $specialChars = ['.', ',', '!', '?']; $excerpt = array_reduce($excerptParts, function (string $excerpt, string $part) use ($specialChars): string { if (in_array(mb_substr($part, -1), $specialChars, true) === false) { - // add comma add end of string if it doesn't have sentence end + // add period at end of string if it doesn't have sentence end $part .= '.'; } diff --git a/src/Utils/ComposeValueHelper.php b/src/Utils/ComposeValueHelper.php index a71985676..3586b2342 100644 --- a/src/Utils/ComposeValueHelper.php +++ b/src/Utils/ComposeValueHelper.php @@ -16,7 +16,7 @@ public static function isSuitable(Content $record, string $which = 'title_format if ($definition !== null && $definition->has($which)) { $format = $definition->get($which); - if (is_string($format) && strpos($format, '{') !== false) { + if (is_string($format) && mb_strpos($format, '{') !== false) { return true; } } @@ -67,22 +67,19 @@ function ($match) use ($record, $locale) { public static function getFieldNames(string $format): array { - $res = preg_match_all('/{([\w]+)}/i', $format, $matches); + preg_match_all('/{([\w]+)}/i', $format, $matches); - dump($matches[1]); return $matches[1]; } - public static function guessTitleFields(Content $content): array { $definition = $content->getDefinition(); // First, see if we have a "title format" in the Content Type. if ($definition !== null && $definition->has('title_format')) { - - if (ComposeValueHelper::isSuitable($content)) { - $names = ComposeValueHelper::getFieldNames($definition->get('title_format')); + if (self::isSuitable($content)) { + $names = self::getFieldNames($definition->get('title_format')); } else { $names = $definition->get('title_format'); } @@ -95,6 +92,7 @@ public static function guessTitleFields(Content $content): array $name )); } + return $content->hasField($name); });