diff --git a/README.md b/README.md
index 46b8aa5..b0c4963 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,31 @@ Comments are loaded automatically via JavaScript when visitors view a blog post.
- Queries the PHP backend to find matching Mastodon toots
- Displays replies as comments with full formatting
+### Optional: Direct Toot URL (Recommended for Performance)
+
+For better performance, you can specify the Mastodon toot URL directly in your post's front matter:
+
+```yaml
+---
+title: "My Post Title"
+mastodon_toot_url: "https://mastodon.social/@username/113456789012345678"
+---
+```
+
+**Benefits:**
+- Skips the entire toot search phase
+- Reduces API calls significantly
+- Faster page loads
+- Works across different Mastodon instances
+- Ensures the correct toot is always used
+
+**When to use:**
+- For any post where you know the Mastodon toot URL
+- Especially recommended for popular or archived posts
+- When you've shared the post on a different Mastodon instance
+
+If no `mastodon_toot_url` is provided, the system automatically falls back to searching for toots containing the post URL.
+
### Force Cache Refresh
To manually clear and rebuild the cache:
diff --git a/layouts/partials/comments.html b/layouts/partials/comments.html
index 8e931b7..1f6368c 100644
--- a/layouts/partials/comments.html
+++ b/layouts/partials/comments.html
@@ -30,3 +30,4 @@
+
diff --git a/static/comments/getcomments.js b/static/comments/getcomments.js
index ac8953e..a2449f9 100644
--- a/static/comments/getcomments.js
+++ b/static/comments/getcomments.js
@@ -28,12 +28,18 @@ $(document).ready(function() {
debugLog('Searching for comments for: ' + RelPermalink);
+ // Check if a direct Mastodon toot URL is provided
+ var ajaxData = { search: RelPermalink };
+ if (MastodonTootUrl && MastodonTootUrl !== "") {
+ // Pass the full URL to PHP so it can extract instance and ID
+ ajaxData.toot_url = MastodonTootUrl;
+ debugLog('Using predefined Mastodon toot URL: ' + MastodonTootUrl);
+ }
+
$.ajax({
url: "/comments/getcomments.php",
type: "get",
- data: {
- search : RelPermalink
- },
+ data: ajaxData,
success: function(data) {
// Enable debug logging if backend has debug enabled
if (data.debug === true) {
diff --git a/static/comments/getcomments.php b/static/comments/getcomments.php
index 89305b1..f32ffa2 100644
--- a/static/comments/getcomments.php
+++ b/static/comments/getcomments.php
@@ -10,8 +10,11 @@ $instance = $config['mastodon-instance'];
$uid = $config['user-id'];
$searchurl = $config['search-url'];
$search = isset($_GET['search']) ? strtolower($_GET['search']) : '';
+$toot_url = isset($_GET['toot_url']) ? $_GET['toot_url'] : null;
$force_refresh = isset($_GET['force_refresh']) && $_GET['force_refresh'] == '1';
$debug_on = $config['debug'];
+
+debug("Request parameters - search: $search, toot_url: " . ($toot_url ? $toot_url : "not provided") . ", force_refresh: " . ($force_refresh ? "yes" : "no"));
/* cache files */
$ctt = $config['cache_toots'];
$dbt = "cache-toots.json";
@@ -45,6 +48,19 @@ function debug($data) {
}
}
+/* Parse Mastodon toot URL to extract instance and toot ID */
+function parseTootUrl($url) {
+ // Expected format: https://instance.example/@username/1234567890
+ // or: https://instance.example/users/username/statuses/1234567890
+ if (preg_match('|^(https?://[^/]+)/.*/(\d+)$|i', $url, $matches)) {
+ return [
+ 'instance' => $matches[1],
+ 'id' => $matches[2]
+ ];
+ }
+ return null;
+}
+
/* CACHE FUNCTIONS */
/* write data to file */
function write_db($db, $data, $id) {
@@ -170,12 +186,41 @@ function tootContextAndStats($instance, $id, &$result) {
* START PROGRAM
***************/
-/* check whether the cached file containing all toots is older than max. cache time */
-// this at the same time loads the cached DB, either way
-$cachebreak = $force_refresh; // Force cache break if requested
-read_db($dbt, $toots, $ctt, $cachebreak, false);
+// create empty $result template
+$result_empty = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]];
+$result = $result_empty;
-if ($cachebreak) {
+/* If toot_url is provided, skip the toot search entirely */
+$toot_instance = $instance; // Default to config instance
+$id = null; // Initialize
+
+if ($toot_url) {
+ $parsed = parseTootUrl($toot_url);
+ if ($parsed) {
+ $id = $parsed['id'];
+ $toot_instance = $parsed['instance'];
+ debug("Toot URL provided: $toot_url");
+ debug("Extracted - Instance: $toot_instance, ID: $id");
+
+ // When using a custom instance, include instance hash in cache filename to avoid collisions
+ if ($toot_instance !== $instance) {
+ $instance_hash = md5($toot_instance);
+ $dbc = "cache-comments_%id-{$instance_hash}.json";
+ debug("Using instance-specific cache file for non-default instance");
+ }
+ } else {
+ debug("Failed to parse toot URL: $toot_url");
+ $toot_url = null; // Fall back to search
+ }
+}
+
+if (!$toot_url) {
+ /* check whether the cached file containing all toots is older than max. cache time */
+ // this at the same time loads the cached DB, either way
+ $cachebreak = $force_refresh; // Force cache break if requested
+ read_db($dbt, $toots, $ctt, $cachebreak, false);
+
+ if ($cachebreak) {
/* Collect all the toots */
/* get id of latest cached toot, and set as $min_id */
debug("Toots cache outdated. Checking for new toots");
@@ -208,24 +253,25 @@ if ($cachebreak) {
}
} else {
debug("Toots cache is up-to-date");
-}
+ }
-// create empty $result
-$result_empty = ['comments' => [], 'stats' => ['reblogs' => 0, 'favs' => 0, 'replies' => 0, 'url' => '', 'root' => 0]];
-$result = $result_empty;
+ /* check if URL from $search exists in $toots */
+ $found_id = null;
+ foreach ($toots as $toot) {
+ if (!empty($toot['url']) && strpos($toot['url'], $search) !== false) {
+ $found_id = $toot['id']; // will keep the oldest (last in array)
+ }
+ }
-/* check if URL from $search exists in $toots */
-$found_id = null;
-foreach ($toots as $toot) {
- if (!empty($toot['url']) && strpos($toot['url'], $search) !== false) {
- $found_id = $toot['id']; // will keep the oldest (last in array)
+ if ($found_id === null) {
+ debug("Blog URL \"$search\" has not been found");
+ } else {
+ $id = $found_id;
}
}
-if ($found_id === null) {
- debug("Blog URL \"$search\" has not been found");
-} else {
- $id = $found_id;
+/* Process comments if we have a toot ID (either from URL or search) */
+if ($id) {
/* read cached comments, or reload new comments if cached data too old */
$cachebreak = false;
@@ -239,7 +285,7 @@ if ($found_id === null) {
$result = $result_empty;
read_db($dbc, $result, $ctc, $cachebreak, $id);
/* Extract comments and stats from toot */
- tootContextAndStats($instance, $id, $result);
+ tootContextAndStats($toot_instance, $id, $result);
// Always count replies manually for accuracy
$result['stats']['replies'] = count($result['comments']);
$result['stats']['root'] = $id;