{"slug": "embedding-status-posts-from-another-bearblog", "title": "Embedding status posts from another Bearblog", "summary": "Sylvia from departure.blog shares a method to embed status posts from one Bearblog into another using a Cloudflare Worker that fetches the Atom feed, adds CORS headers, and caches it for an hour. The worker script and embedding JavaScript are provided, with the latest 10 posts displayed on the homepage.", "body_md": "# Embedding status posts from another Bearblog\n\n*\n*\n\nI shared in [Weeknotes 2026-18](/weeknotes-2026-18/#puttering):\n\nI've been wanting to embed a second Bearblog's posts to my main Bearblog for a long time now and I finally figured out how to do it. My tiny posts are Powered by Bear ʕ•ᴥ•ʔ again and live over at status.departure.blog / sylvia-status.bearblog.dev. The latest 10 posts are embedded on my homepage with the help of Cloudfare Workers (it pulls the Atom feed, adds the missing CORS header, and caches it).\n\nThis is how I did it. I'm a JavaScript newb, so the scripts I'm sharing here were created with Claude's assistance.\n\n## Create a worker to fetch the Atom feed\n\n- Log into Cloudfare Dashboard (free for personal / hobby projects)\n- Go to\n**Compute**>** Workers & Pages** - Select\n**Create Application** in the top right - Select\n**Start with Hello World!** - Name the worker (or use the default gibberish, which is what I do)\n- Select\n**Deploy**(which redirects to the new worker's Overview page) - Select\n**Edit code** in the top right - Delete everything in\n**worker.js** - Paste in the worker.js below (update the Bearblog feed URL)\n- Select\n**Deploy** in the top right\n\n### Add to worker.js\n\nThis pulls the feed, caches it for an hour, and adds a CORS header so it can be embedded on another Bearblog.\n\n``` js\nexport default {\n  async fetch(request, env, ctx) {\n    const TARGET = \"https://user-status.bearblog.dev/feed/\";\n    const cache = caches.default;\n\n    let response = await cache.match(TARGET);\n    if (response) return response;\n\n    response = await fetch(TARGET, {\n      headers: {\n        \"User-Agent\": \"feed-fetcher/1.0\"\n      }\n    });\n    const body = await response.text();\n\n    const cachedResponse = new Response(body, {\n      headers: {\n        \"Content-Type\": response.headers.get(\"Content-Type\") || \"application/xml\",\n        \"Access-Control-Allow-Origin\": \"*\",\n        \"Cache-Control\": \"public, max-age=3600\",\n      },\n    });\n\n    ctx.waitUntil(cache.put(TARGET, cachedResponse.clone()));\n    return cachedResponse;\n  }\n};\n```\n\n## Embed the feed's posts into Bearblog\n\n- Create a Bearblog page\n- Paste the following HTML + JavaScript into the page (update the Cloudfare Workers URL)\n- Select\n**Publish**\n\n### Add to where posts should display\n\n``` php\n<!-- Embed status posts from another Bearblog -->\n<div id=\"posts\"><p>Loading...</p></div>\n```\n\n### Add to bottom of the same page\n\nThis pulls the worker's feed and renders it as HTML, following Bearblog's HTML structure and my preferred timestamp format. It finds the `#posts`\n\ncontainer and lists the posts within it.\n\n``` php\n<!-- Embed status posts from another Bearblog -->\n<script>\n  fetch(\"https://worker-name.user.workers.dev\")\n    .then(r => r.text())\n    .then(str => new DOMParser().parseFromString(str, \"application/xml\"))\n    .then(xml => {\n      const entries = [...xml.querySelectorAll(\"entry\")];\n\n      if (entries.length === 0) {\n        document.getElementById(\"posts\").innerHTML = \"<p>No posts found.</p>\";\n        return;\n      }\n\n      const now = new Date();\n\n      const items = entries.map(entry => {\n        const link = entry.querySelector(\"link\").getAttribute(\"href\");\n        const content = entry.querySelector(\"content\").textContent;\n        const title = entry.querySelector(\"title\").textContent;\n        const published = entry.querySelector(\"published\").textContent;\n        const date = new Date(published);\n\n        const isToday = date.getDate() === now.getDate() &&\n          date.getMonth() === now.getMonth() &&\n          date.getFullYear() === now.getFullYear();\n\n        const hours = date.getHours().toString().padStart(2, '0');\n        const minutes = date.getMinutes().toString().padStart(2, '0');\n        const timeStr = `${hours}:${minutes}`;\n\n        const dateStr = date.toLocaleDateString(\"en-GB\", {\n          day: \"2-digit\",\n          month: \"short\",\n          year: \"numeric\",\n        });\n\n        const timestamp = isToday ? `Today @ ${timeStr}` : `${dateStr} @ ${timeStr}`;\n\n        return `\n          <li data-tags=\"status\">\n            <span><i><time datetime=\"${published}\">${timestamp}</time></i></span>\n            <a href=\"${link}\">${title}</a>\n            <div>${content}</div>\n          </li>\n        `;\n      }).join(\"\");\n\n      document.getElementById(\"posts\").innerHTML = `<ul class=\"embedded blog-posts\" style=\"margin-top: 0;\">${items}</ul>`;\n    })\n    .catch(() => {\n      document.getElementById(\"posts\").innerHTML = \"<p>Posts failed to load.</p>\";\n    });\n</script>\n```\n\n### Re: [My theme v3](/theme-v3/#home)\n\nOn the homepage, replace:\n\n```\n<section class=\"status\">\n\n## These days\n\n{{ posts | tag:status | content:True | limit:10 }}\n\n[View more small thoughts](/status/) →\n\n</section>\n```\n\nWith:\n\n```\n<section class=\"status\">\n\n## These days\n\n<!-- Embed status posts from another Bearblog -->\n<div id=\"posts\"><p>Loading...</p></div>\n\n[View more small thoughts](https://user-status.bearblog.dev/) →\n\n</section>\n```\n\nAnd then add [the script](#add-to-bottom-of-the-same-page) at the end of the homepage.", "url": "https://wpnews.pro/news/embedding-status-posts-from-another-bearblog", "canonical_source": "https://departure.blog/embedding-status-posts-from-another-bearblog/", "published_at": "2026-07-21 12:02:03+00:00", "updated_at": "2026-07-21 12:23:21.927733+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Cloudflare", "Bearblog", "Claude", "departure.blog", "sylvia-status.bearblog.dev"], "alternates": {"html": "https://wpnews.pro/news/embedding-status-posts-from-another-bearblog", "markdown": "https://wpnews.pro/news/embedding-status-posts-from-another-bearblog.md", "text": "https://wpnews.pro/news/embedding-status-posts-from-another-bearblog.txt", "jsonld": "https://wpnews.pro/news/embedding-status-posts-from-another-bearblog.jsonld"}}