diff --git a/app/Http/Controllers/ArtistsController.php b/app/Http/Controllers/ArtistsController.php
index 1a63b4680f3..262a7743c24 100644
--- a/app/Http/Controllers/ArtistsController.php
+++ b/app/Http/Controllers/ArtistsController.php
@@ -111,6 +111,8 @@ public function show($id)
}
}
+ set_opengraph($artist);
+
return ext_view('artists.show', [
'artist' => $artist,
'images' => $images,
diff --git a/app/Http/Controllers/BeatmapsetsController.php b/app/Http/Controllers/BeatmapsetsController.php
index 69623a70e32..4f0a90663b9 100644
--- a/app/Http/Controllers/BeatmapsetsController.php
+++ b/app/Http/Controllers/BeatmapsetsController.php
@@ -102,6 +102,8 @@ public function show($id)
$noindex = !$beatmapset->esShouldIndex();
+ set_opengraph($beatmapset);
+
return ext_view('beatmapsets.show', compact(
'beatmapset',
'commentBundle',
diff --git a/app/Http/Controllers/CommentsController.php b/app/Http/Controllers/CommentsController.php
index b89ce074b41..a85024632c9 100644
--- a/app/Http/Controllers/CommentsController.php
+++ b/app/Http/Controllers/CommentsController.php
@@ -161,6 +161,8 @@ public function show($id)
return $commentBundle->toArray();
}
+ set_opengraph($comment);
+
return ext_view('comments.show', compact('commentBundle'));
}
diff --git a/app/Http/Controllers/ContestsController.php b/app/Http/Controllers/ContestsController.php
index 3ed5d131fd4..e3c8caf0327 100644
--- a/app/Http/Controllers/ContestsController.php
+++ b/app/Http/Controllers/ContestsController.php
@@ -42,6 +42,8 @@ public function show($id)
$contests = collect([$contest]);
}
+ set_opengraph($contest);
+
if ($contest->isVotingStarted()) {
if ($contest->isVotingOpen()) {
// TODO: add support for $contests requirement instead of at parent
diff --git a/app/Http/Controllers/Forum/ForumsController.php b/app/Http/Controllers/Forum/ForumsController.php
index d5450dcbf9b..61050780d07 100644
--- a/app/Http/Controllers/Forum/ForumsController.php
+++ b/app/Http/Controllers/Forum/ForumsController.php
@@ -105,6 +105,8 @@ public function show($id)
$noindex = !$forum->enable_indexing;
+ set_opengraph($forum);
+
return ext_view('forum.forums.show', compact(
'cover',
'forum',
diff --git a/app/Http/Controllers/Forum/TopicsController.php b/app/Http/Controllers/Forum/TopicsController.php
index acc6b8627fc..ea784a58317 100644
--- a/app/Http/Controllers/Forum/TopicsController.php
+++ b/app/Http/Controllers/Forum/TopicsController.php
@@ -429,7 +429,7 @@ public function show($id)
$posts->last()->markRead($currentUser);
- $coverModel = $topic->cover()->firstOrNew([]);
+ $coverModel = $topic->cover ?? new TopicCover();
$coverModel->setRelation('topic', $topic);
$cover = json_item($coverModel, new TopicCoverTransformer());
@@ -438,6 +438,8 @@ public function show($id)
$featureVotes = $this->groupFeatureVotes($topic);
$noindex = !$topic->forum->enable_indexing;
+ set_opengraph($topic);
+
return ext_view('forum.topics.show', compact(
'canEditPoll',
'cover',
diff --git a/app/Http/Controllers/NewsController.php b/app/Http/Controllers/NewsController.php
index 80e7e49308f..8fa04aeb12a 100644
--- a/app/Http/Controllers/NewsController.php
+++ b/app/Http/Controllers/NewsController.php
@@ -194,6 +194,8 @@ public function show($slug)
return $postJson;
}
+ set_opengraph($post);
+
return ext_view('news.show', [
'commentBundle' => CommentBundle::forEmbed($post),
'post' => $post,
diff --git a/app/Http/Controllers/Users/ModdingHistoryController.php b/app/Http/Controllers/Users/ModdingHistoryController.php
index 24b335984c1..86f1670faf9 100644
--- a/app/Http/Controllers/Users/ModdingHistoryController.php
+++ b/app/Http/Controllers/Users/ModdingHistoryController.php
@@ -47,6 +47,8 @@ public function index()
$jsonChunks = ModdingHistoryEventsBundle::forProfile($user, $this->searchParams)->toArray();
+ set_opengraph($this->user, 'modding');
+
return ext_view('users.beatmapset_activities', compact(
'jsonChunks',
'user'
diff --git a/app/Http/Controllers/Users/MultiplayerController.php b/app/Http/Controllers/Users/MultiplayerController.php
index a81a4a371e0..f5d3abbca4c 100644
--- a/app/Http/Controllers/Users/MultiplayerController.php
+++ b/app/Http/Controllers/Users/MultiplayerController.php
@@ -36,6 +36,8 @@ public function index($userId, $typeGroup)
return $json;
}
+ set_opengraph($user, 'multiplayer');
+
$jsonUser = json_item(
$user,
(new UserTransformer())->setMode($user->playmode),
diff --git a/app/Http/Controllers/UsersController.php b/app/Http/Controllers/UsersController.php
index b2648674a75..d772a59285e 100644
--- a/app/Http/Controllers/UsersController.php
+++ b/app/Http/Controllers/UsersController.php
@@ -631,7 +631,7 @@ public function show($id, $mode = null)
abort(404);
}
- // preload and set relation for toMetaDescription and transformer sharing data
+ // preload and set relation for opengraph header and transformer sharing data
$user->statistics($currentMode)?->setRelation('user', $user);
$userArray = $this->fillDeprecatedDuplicateFields(json_item(
@@ -654,9 +654,9 @@ public function show($id, $mode = null)
'user' => $userArray,
];
- $pageDescription = blade_safe($user->toMetaDescription(['ruleset' => $currentMode]));
+ set_opengraph($user, 'show', $currentMode);
- return ext_view('users.show', compact('initialData', 'pageDescription', 'mode', 'user'));
+ return ext_view('users.show', compact('initialData', 'mode', 'user'));
}
}
diff --git a/app/Http/Controllers/WikiController.php b/app/Http/Controllers/WikiController.php
index b735db094e2..78368135ae4 100644
--- a/app/Http/Controllers/WikiController.php
+++ b/app/Http/Controllers/WikiController.php
@@ -107,6 +107,8 @@ public function show($locale = null, $path = null)
return json_item($page, 'WikiPage');
}
+ set_opengraph($page);
+
return ext_view(
$page->template(),
['contentLocale' => $page->locale, 'page' => $page],
diff --git a/app/Libraries/Opengraph/ArtistOpengraph.php b/app/Libraries/Opengraph/ArtistOpengraph.php
new file mode 100644
index 00000000000..98b274f9107
--- /dev/null
+++ b/app/Libraries/Opengraph/ArtistOpengraph.php
@@ -0,0 +1,26 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\Artist;
+
+class ArtistOpengraph implements OpengraphInterface
+{
+ public function __construct(private Artist $artist)
+ {
+ }
+
+ public function get(): array
+ {
+ return [
+ 'description' => first_paragraph(markdown_plain($this->artist->description)),
+ 'image' => $this->artist->cover_url,
+ 'title' => $this->artist->name,
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/BeatmapsetOpengraph.php b/app/Libraries/Opengraph/BeatmapsetOpengraph.php
new file mode 100644
index 00000000000..ae6cec6099f
--- /dev/null
+++ b/app/Libraries/Opengraph/BeatmapsetOpengraph.php
@@ -0,0 +1,29 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\Beatmapset;
+
+class BeatmapsetOpengraph implements OpengraphInterface
+{
+ public function __construct(private Beatmapset $beatmapset)
+ {
+ }
+
+ public function get(): array
+ {
+ $section = osu_trans('layout.menu.beatmaps._');
+ $title = "{$this->beatmapset->artist} - {$this->beatmapset->title}"; // opengraph header always intended for guest.
+
+ return [
+ 'description' => "osu! » {$section} » {$title}",
+ 'image' => $this->beatmapset->coverURL('card'),
+ 'title' => $title,
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/CommentOpengraph.php b/app/Libraries/Opengraph/CommentOpengraph.php
new file mode 100644
index 00000000000..8aa4cdb9612
--- /dev/null
+++ b/app/Libraries/Opengraph/CommentOpengraph.php
@@ -0,0 +1,29 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\Comment;
+
+class CommentOpengraph implements OpengraphInterface
+{
+ public function __construct(private Comment $comment)
+ {
+ }
+
+ public function get(): array
+ {
+ $user = $this->comment->user;
+
+ return priv_check_user(null, 'CommentShow', $this->comment)->can()
+ ? [
+ 'description' => blade_safe(html_excerpt($this->comment->message_html, 100)),
+ 'image' => $user->user_avatar,
+ 'title' => osu_trans('comments.ogp.title', ['user' => $user->username]),
+ ] : [];
+ }
+}
diff --git a/app/Libraries/Opengraph/ContestOpengraph.php b/app/Libraries/Opengraph/ContestOpengraph.php
new file mode 100644
index 00000000000..5bf4a188e27
--- /dev/null
+++ b/app/Libraries/Opengraph/ContestOpengraph.php
@@ -0,0 +1,26 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\Contest;
+
+class ContestOpengraph implements OpengraphInterface
+{
+ public function __construct(private Contest $contest)
+ {
+ }
+
+ public function get(): array
+ {
+ return [
+ 'description' => strip_tags(markdown($this->contest->currentDescription())),
+ 'image' => $this->contest->header_url,
+ 'title' => $this->contest->name,
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/Forum/ForumOpengraph.php b/app/Libraries/Opengraph/Forum/ForumOpengraph.php
new file mode 100644
index 00000000000..6d730161cc4
--- /dev/null
+++ b/app/Libraries/Opengraph/Forum/ForumOpengraph.php
@@ -0,0 +1,41 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph\Forum;
+
+use App\Libraries\Opengraph\OpengraphInterface;
+use App\Models\Forum\Forum;
+
+class ForumOpengraph implements OpengraphInterface
+{
+ public function __construct(private Forum $forum)
+ {
+ }
+
+ // Reminder to update Topic::toOpengraph() as necessary if this value changes.
+ public function description(): string
+ {
+ $stack = [osu_trans('forum.title')];
+ foreach ($this->forum->forum_parents as $forumId => $forumData) {
+ $stack[] = $forumData[0];
+ }
+
+ $stack[] = $this->forum->forum_name;
+
+ return implode(' » ', $stack);
+ }
+
+ public function get(): array
+ {
+
+ return [
+ 'description' => $this->description(),
+ 'title' => $this->forum->forum_name,
+ 'image' => $this->forum->cover?->fileUrl(),
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/Forum/TopicOpengraph.php b/app/Libraries/Opengraph/Forum/TopicOpengraph.php
new file mode 100644
index 00000000000..1db89abe3d3
--- /dev/null
+++ b/app/Libraries/Opengraph/Forum/TopicOpengraph.php
@@ -0,0 +1,29 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph\Forum;
+
+use App\Libraries\Opengraph\OpengraphInterface;
+use App\Models\Forum\Topic;
+
+class TopicOpengraph implements OpengraphInterface
+{
+ public function __construct(private Topic $topic)
+ {
+ }
+
+ public function get(): array
+ {
+ $forumDescription = (new ForumOpengraph($this->topic->forum))->description();
+
+ return [
+ 'description' => "{$forumDescription} » {$this->topic->topic_title}",
+ 'image' => $this->topic->cover?->fileUrl() ?? $this->topic->forum->cover?->defaultTopicCover->fileUrl(),
+ 'title' => $this->topic->topic_title,
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/NewsPostOpengraph.php b/app/Libraries/Opengraph/NewsPostOpengraph.php
new file mode 100644
index 00000000000..5939cd8e8a9
--- /dev/null
+++ b/app/Libraries/Opengraph/NewsPostOpengraph.php
@@ -0,0 +1,26 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\NewsPost;
+
+class NewsPostOpengraph implements OpengraphInterface
+{
+ public function __construct(private NewsPost $post)
+ {
+ }
+
+ public function get(): array
+ {
+ return [
+ 'description' => $this->post->previewText(),
+ 'image' => $this->post->firstImage(true),
+ 'title' => $this->post->title(),
+ ];
+ }
+}
diff --git a/app/Libraries/Opengraph/OpengraphInterface.php b/app/Libraries/Opengraph/OpengraphInterface.php
new file mode 100644
index 00000000000..cec159c4673
--- /dev/null
+++ b/app/Libraries/Opengraph/OpengraphInterface.php
@@ -0,0 +1,13 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+interface OpengraphInterface
+{
+ public function get(): array;
+}
diff --git a/app/Libraries/Opengraph/UserOpengraph.php b/app/Libraries/Opengraph/UserOpengraph.php
new file mode 100644
index 00000000000..f4278d6715b
--- /dev/null
+++ b/app/Libraries/Opengraph/UserOpengraph.php
@@ -0,0 +1,85 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph;
+
+use App\Models\Beatmap;
+use App\Models\User;
+
+class UserOpengraph implements OpengraphInterface
+{
+ public static function escapeForTitle(string $username)
+ {
+ return blade_safe(str_replace(' ', ' ', e($username)));
+ }
+
+ public function __construct(private User $user, private string $page, private ?string $ruleset = null)
+ {
+ }
+
+ public function get(): array
+ {
+ return [
+ // none for multiplayer, playlist counts seems...not useful?
+ 'description' => $this->page === 'modding' ? $this->moddingDescription() : $this->showDescription(),
+ 'image' => $this->user->user_avatar,
+ 'title' => static::escapeForTitle($this->user->username),
+ ];
+ }
+
+ private function moddingDescription(): string
+ {
+ static $statuses = ['ranked', 'loved', 'pending', 'graveyard'];
+
+ $countsText = [];
+ foreach ($statuses as $status) {
+ $count = $this->user->profileBeatmapsetCountByGroupedStatus($status);
+ if ($count > 0) {
+ $countsText[] = osu_trans("beatmapsets.show.status.{$status}").' '.number_format($count);
+ }
+ }
+
+ return empty($countsText)
+ ? osu_trans('users.ogp.modding_description_empty')
+ : osu_trans('users.ogp.modding_description', [
+ 'counts' => implode(' | ', $countsText),
+ ]);
+ }
+
+ private function showDescription(): string
+ {
+ static $rankTypes = ['country', 'global'];
+
+ $ruleset = $this->ruleset ?? $this->user->playmode;
+ $stats = $this->user->statistics($ruleset);
+
+ $replacements['ruleset'] = $ruleset;
+
+ foreach ($rankTypes as $type) {
+ $method = "{$type}Rank";
+ $replacements[$type] = osu_trans("users.ogp.description.{$type}", [
+ 'rank' => format_rank($stats?->$method()),
+ ]);
+
+ $variants = Beatmap::VARIANTS[$ruleset] ?? [];
+
+ $variantsTexts = null;
+ foreach ($variants as $variant) {
+ $variantRank = $this->user->statistics($ruleset, false, $variant)?->$method();
+ if ($variantRank !== null) {
+ $variantsTexts[] = $variant.' '.format_rank($variantRank);
+ }
+ }
+
+ if (!empty($variantsTexts)) {
+ $replacements[$type] .= ' ('.implode(', ', $variantsTexts).')';
+ }
+ }
+
+ return osu_trans('users.ogp.description._', $replacements);
+ }
+}
diff --git a/app/Libraries/Opengraph/Wiki/PageOpengraph.php b/app/Libraries/Opengraph/Wiki/PageOpengraph.php
new file mode 100644
index 00000000000..697f1799bc7
--- /dev/null
+++ b/app/Libraries/Opengraph/Wiki/PageOpengraph.php
@@ -0,0 +1,30 @@
+. Licensed under the GNU Affero General Public License v3.0.
+// See the LICENCE file in the repository root for full licence text.
+
+declare(strict_types=1);
+
+namespace App\Libraries\Opengraph\Wiki;
+
+use App\Libraries\Opengraph\OpengraphInterface;
+use App\Models\Wiki\Page;
+
+class PageOpengraph implements OpengraphInterface
+{
+ public function __construct(private Page $page)
+ {
+ }
+
+ public function get(): array
+ {
+ if (!$this->page->isVisible()) {
+ return [];
+ }
+
+ return [
+ 'description' => $this->page->getTextPreview(),
+ 'title' => $this->page->title(),
+ ];
+ }
+}
diff --git a/app/Models/Beatmapset.php b/app/Models/Beatmapset.php
index 79512b546ce..520271a54f0 100644
--- a/app/Models/Beatmapset.php
+++ b/app/Models/Beatmapset.php
@@ -1421,13 +1421,6 @@ public function updateDescription($bbcode, $user)
]);
}
- public function toMetaDescription()
- {
- $section = osu_trans('layout.menu.beatmaps._');
-
- return "osu! » {$section} » {$this->artist} - {$this->title}";
- }
-
private function extractDescription($post)
{
// Any description (after the first match) that matches
diff --git a/app/Models/Comment.php b/app/Models/Comment.php
index 67a039cea05..b249fcaa4d5 100644
--- a/app/Models/Comment.php
+++ b/app/Models/Comment.php
@@ -6,6 +6,7 @@
namespace App\Models;
use App\Libraries\MorphMap;
+use App\Traits\Memoizes;
use App\Traits\Validatable;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
@@ -39,7 +40,7 @@
*/
class Comment extends Model implements Traits\ReportableInterface
{
- use Traits\Reportable, Traits\WithDbCursorHelper, Validatable;
+ use Memoizes, Traits\Reportable, Traits\WithDbCursorHelper, Validatable;
const COMMENTABLES = [
MorphMap::MAP[Beatmapset::class],
@@ -122,6 +123,8 @@ public function replies()
public function setMessageAttribute($value)
{
+ $this->resetMemoized();
+
return $this->attributes['message'] = trim(unzalgo($value));
}
@@ -169,6 +172,7 @@ public function getAttribute($key)
'pinned' => (bool) $this->getRawAttribute($key),
'disqus_user_data' => $this->getDisqusUserData(),
+ 'message_html' => $this->getMessageHtml(),
'commentable',
'editor',
@@ -308,4 +312,9 @@ private function getDisqusUserData(): ?array
return $value === null ? null : json_decode($value, true);
}
+
+ private function getMessageHtml(): ?string
+ {
+ return $this->memoize(__FUNCTION__, fn () => markdown($this->message, 'comment'));
+ }
}
diff --git a/app/Models/Forum/Forum.php b/app/Models/Forum/Forum.php
index cf61fb0a7a4..82a24493270 100644
--- a/app/Models/Forum/Forum.php
+++ b/app/Models/Forum/Forum.php
@@ -373,16 +373,4 @@ public function markAsRead(User $user, bool $recursive = false)
TopicTrack::where('user_id', $user->getKey())->whereIn('forum_id', $forumIds)->delete();
});
}
-
- public function toMetaDescription()
- {
- $stack = [osu_trans('forum.title')];
- foreach ($this->forum_parents as $forumId => $forumData) {
- $stack[] = $forumData[0];
- }
-
- $stack[] = $this->forum_name;
-
- return implode(' » ', $stack);
- }
}
diff --git a/app/Models/Forum/Topic.php b/app/Models/Forum/Topic.php
index 15832714316..ea0d9c426f9 100644
--- a/app/Models/Forum/Topic.php
+++ b/app/Models/Forum/Topic.php
@@ -824,11 +824,6 @@ public function hasIssueTag($tag)
return strpos($this->topic_title, "[{$tag}]") !== false;
}
- public function toMetaDescription()
- {
- return "{$this->forum->toMetaDescription()} » {$this->topic_title}";
- }
-
public function afterCommit()
{
if ($this->exists && $this->firstPost !== null) {
diff --git a/app/Models/User.php b/app/Models/User.php
index 3c81fc5e2e8..013951fe5a7 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -1814,39 +1814,6 @@ public function titleUrl(): ?string
return $this->rank?->url;
}
- public function toMetaDescription(array $options = []): string
- {
- static $rankTypes = ['country', 'global'];
-
- $ruleset = $options['ruleset'] ?? $this->playmode;
- $stats = $this->statistics($ruleset);
-
- $replacements['ruleset'] = $ruleset;
-
- foreach ($rankTypes as $type) {
- $method = "{$type}Rank";
- $replacements[$type] = osu_trans("users.ogp.description.{$type}", [
- 'rank' => format_rank($stats?->$method()),
- ]);
-
- $variants = Beatmap::VARIANTS[$ruleset] ?? [];
-
- $variantsTexts = null;
- foreach ($variants as $variant) {
- $variantRank = $this->statistics($ruleset, false, $variant)?->$method();
- if ($variantRank !== null) {
- $variantsTexts[] = $variant.' '.format_rank($variantRank);
- }
- }
-
- if (!empty($variantsTexts)) {
- $replacements[$type] .= ' ('.implode(', ', $variantsTexts).')';
- }
- }
-
- return osu_trans('users.ogp.description._', $replacements);
- }
-
public function hasProfile()
{
return $this->getKey() !== null
diff --git a/app/Models/Wiki/Page.php b/app/Models/Wiki/Page.php
index a055c574f5f..d0b7bd29129 100644
--- a/app/Models/Wiki/Page.php
+++ b/app/Models/Wiki/Page.php
@@ -228,7 +228,7 @@ public function esIndexDocument(array $options = [])
public function esFetch()
{
$response = (new BasicSearch(static::esIndexName(), 'wiki_page_lookup'))
- ->source(['markdown', 'page', 'indexed_at', 'version'])
+ ->source(['markdown', 'page', 'page_text', 'indexed_at', 'version'])
->query([
'term' => [
'_id' => $this->pagePath(),
@@ -251,6 +251,11 @@ public function getMarkdown()
return $this->source['markdown'] ?? null;
}
+ public function getTextPreview()
+ {
+ return html_excerpt($this->source['page_text']);
+ }
+
public function hasParent()
{
return $this->parent() !== null;
diff --git a/app/Transformers/CommentTransformer.php b/app/Transformers/CommentTransformer.php
index 86237f177f1..64dfe893cb8 100644
--- a/app/Transformers/CommentTransformer.php
+++ b/app/Transformers/CommentTransformer.php
@@ -62,7 +62,7 @@ public function includeMessage(Comment $comment)
public function includeMessageHtml(Comment $comment)
{
- return $this->primitive(markdown($comment->message, 'comment'));
+ return $this->primitive($comment->message_html);
}
public function includeUser(Comment $comment)
diff --git a/app/helpers.php b/app/helpers.php
index 3099aa3de6c..17a7ed2f54c 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -1676,6 +1676,13 @@ function seeded_shuffle(array &$items, int $seed = 0)
mt_srand();
}
+function set_opengraph($model, ...$options)
+{
+ $className = str_replace('App\Models', 'App\Libraries\Opengraph', $model::class).'Opengraph';
+
+ Request::instance()->attributes->set('opengraph', (new $className($model, ...$options))->get());
+}
+
function first_paragraph($html, $split_on = "\n")
{
$text = strip_tags($html);
diff --git a/resources/lang/en/comments.php b/resources/lang/en/comments.php
index 0aac70ce8dd..9c2939f22e1 100644
--- a/resources/lang/en/comments.php
+++ b/resources/lang/en/comments.php
@@ -43,6 +43,10 @@
'no_comments' => 'no comments found...',
],
+ 'ogp' => [
+ 'title' => 'comment by :user',
+ ],
+
'placeholder' => [
'edit' => 'Edit the comment here',
'new' => 'Type new comment here',
diff --git a/resources/lang/en/users.php b/resources/lang/en/users.php
index 23c2adf8712..97eadd7277a 100644
--- a/resources/lang/en/users.php
+++ b/resources/lang/en/users.php
@@ -124,6 +124,9 @@
],
'ogp' => [
+ 'modding_description' => 'Beatmaps: :counts',
+ 'modding_description_empty' => 'User doesn\'t have any beatmaps...',
+
'description' => [
'_' => 'Rank (:ruleset): :global | :country',
'country' => 'Country :rank',
@@ -183,7 +186,6 @@
'origin_country' => 'From :country',
'previous_usernames' => 'formerly known as',
'plays_with' => 'Plays with :devices',
- 'title' => ":username's profile",
'comments_count' => [
'_' => 'Posted :link',
diff --git a/resources/views/artists/show.blade.php b/resources/views/artists/show.blade.php
index 2da9ce799df..44ae241fb03 100644
--- a/resources/views/artists/show.blade.php
+++ b/resources/views/artists/show.blade.php
@@ -20,12 +20,7 @@
@extends('master', [
'titlePrepend' => $artist->name,
- 'pageDescription' => $artist->description,
'canonicalUrl' => $artist->url(),
- 'opengraph' => [
- 'title' => $artist->name,
- 'image' => $artist->cover_url,
- ],
])
@section('content')
diff --git a/resources/views/beatmapsets/show.blade.php b/resources/views/beatmapsets/show.blade.php
index 14e3036f4b0..0adb9b9c84d 100644
--- a/resources/views/beatmapsets/show.blade.php
+++ b/resources/views/beatmapsets/show.blade.php
@@ -10,7 +10,6 @@
@endphp
@endif
@extends('master', [
- 'pageDescription' => $beatmapset->toMetaDescription(),
'titlePrepend' => "{$beatmapset->getDisplayArtist(auth()->user())} - {$beatmapset->getDisplayTitle(auth()->user())}",
'extraFooterLinks' => $extraFooterLinks ?? [],
])
diff --git a/resources/views/contests/base.blade.php b/resources/views/contests/base.blade.php
index 5878a9f63cf..325ec0f0a54 100644
--- a/resources/views/contests/base.blade.php
+++ b/resources/views/contests/base.blade.php
@@ -17,12 +17,7 @@
@extends('master', [
'titlePrepend' => $contestMeta->name,
- 'pageDescription' => strip_tags(markdown($contestMeta->currentDescription())),
'canonicalUrl' => $contestMeta->url(),
- 'opengraph' => [
- 'title' => $contestMeta->name,
- 'image' => $contestMeta->header_url,
- ],
])
@section('content')
diff --git a/resources/views/forum/forums/show.blade.php b/resources/views/forum/forums/show.blade.php
index d658854a59e..34b7923ae5c 100644
--- a/resources/views/forum/forums/show.blade.php
+++ b/resources/views/forum/forums/show.blade.php
@@ -4,7 +4,6 @@
--}}
@extends('master', [
'bodyAdditionalClasses' => "t-forum-{$forum->categorySlug()}",
- 'pageDescription' => $forum->toMetaDescription(),
'searchParams' => [
'forum_id' => $forum->getKey(),
'mode' => 'forum_post',
diff --git a/resources/views/forum/topics/show.blade.php b/resources/views/forum/topics/show.blade.php
index 7008cdc8940..f397db7e6c8 100644
--- a/resources/views/forum/topics/show.blade.php
+++ b/resources/views/forum/topics/show.blade.php
@@ -5,7 +5,6 @@
@extends('master', [
'titlePrepend' => $topic->topic_title,
'canonicalUrl' => route('forum.topics.show', $topic->topic_id),
- 'pageDescription' => $topic->toMetaDescription(),
])
@php
diff --git a/resources/views/layout/metadata.blade.php b/resources/views/layout/metadata.blade.php
index 74aeb7331f7..ef0937c3d7e 100644
--- a/resources/views/layout/metadata.blade.php
+++ b/resources/views/layout/metadata.blade.php
@@ -6,6 +6,9 @@
$appUrl = config('app.url');
$currentLocale = App::getLocale();
$fallbackLocale = config('app.fallback_locale');
+ $opengraph = Request::instance()->attributes->get('opengraph');
+
+ $opengraph['description'] ??= $pageDescription ?? null;
@endphp
@@ -16,23 +19,28 @@
{{-- @osu-colour-b1 --}}
-
+
-@if (isset($opengraph))
-
-
+
+
+
+@if (isset($canonicalUrl))
-
-
+@endif
- @if (isset($pageDescription))
-
+@foreach ($opengraph as $key => $value)
+ @if (present($value))
+ @if ($key === 'title')
+
+ @else
+
+ @endif
@endif
-@endif
+@endforeach
@if ($noindex ?? false)
diff --git a/resources/views/news/show.blade.php b/resources/views/news/show.blade.php
index a0ca40ecb02..6c24b760ba2 100644
--- a/resources/views/news/show.blade.php
+++ b/resources/views/news/show.blade.php
@@ -2,17 +2,9 @@
Copyright (c) ppy Pty Ltd . Licensed under the GNU Affero General Public License v3.0.
See the LICENCE file in the repository root for full licence text.
--}}
-@php
- $title = $post->title();
-@endphp
@extends('master', [
- 'titlePrepend' => $title,
+ 'titlePrepend' => $post->title(),
'canonicalUrl' => $post->url(),
- 'pageDescription' => blade_safe($post->previewText()),
- 'opengraph' => [
- 'title' => $title,
- 'image' => $post->firstImage(true),
- ],
])
@section('content')
diff --git a/resources/views/users/beatmapset_activities.blade.php b/resources/views/users/beatmapset_activities.blade.php
index b7056ee9c8e..3e11a8a6990 100644
--- a/resources/views/users/beatmapset_activities.blade.php
+++ b/resources/views/users/beatmapset_activities.blade.php
@@ -3,8 +3,8 @@
See the LICENCE file in the repository root for full licence text.
--}}
@extends('master', [
- 'titlePrepend' => blade_safe(str_replace(' ', ' ', e($user->username))),
'pageDescription' => page_description($user->username),
+ 'titlePrepend' => App\Libraries\Opengraph\UserOpengraph::escapeForTitle($user->username),
])
@section('content')
diff --git a/resources/views/users/multiplayer/index.blade.php b/resources/views/users/multiplayer/index.blade.php
index dd45d59b228..a8314be0b0c 100644
--- a/resources/views/users/multiplayer/index.blade.php
+++ b/resources/views/users/multiplayer/index.blade.php
@@ -3,7 +3,7 @@
See the LICENCE file in the repository root for full licence text.
--}}
@extends('master', [
- 'titlePrepend' => blade_safe(str_replace(' ', ' ', e($user->username))),
+ 'titlePrepend' => App\Libraries\Opengraph\UserOpengraph::escapeForTitle($user->username),
'pageDescription' => page_description($user->username),
])
diff --git a/resources/views/users/show.blade.php b/resources/views/users/show.blade.php
index c1a8269adf1..db1f7bdadfc 100644
--- a/resources/views/users/show.blade.php
+++ b/resources/views/users/show.blade.php
@@ -5,11 +5,7 @@
@extends('master', [
'canonicalUrl' => $user->url($mode),
- 'titlePrepend' => blade_safe(str_replace(' ', ' ', e($user->username))),
- 'opengraph' => [
- 'title' => blade_safe(osu_trans('users.show.title', ['username' => $user->username])),
- 'image' => $user->user_avatar,
- ]
+ 'titlePrepend' => App\Libraries\Opengraph\UserOpengraph::escapeForTitle($user->username),
])
@section('content')