{ "type": "entry", "author": { "name": "Colin Devroe", "url": "http://cdevroe.com/author/cdevroe/", "photo": "http://0.gravatar.com/avatar/c248217e9cdc83ce95acc615199ce57f?s=512&d=http://cdevroe.com/wp-content/plugins/semantic-linkbacks/img/mm.jpg&r=g" }, "url": "http://cdevroe.com/2019/05/08/bokeh-kickstarter/", "name": "Bokeh: Private, independent, and user-funded photo sharing", "content": { "html": "<p><a href=\"https://brightpixels.blog/2019/05/bokeh-is-on-kickstarter\">Timothy Smith</a>, on trying to promote <a href=\"https://www.kickstarter.com/projects/timothybsmith/bokeh-private-independent-and-user-funded-photo-sh\">his Kickstarter for Bokeh</a>:</p>\n\n\n\n<blockquote><p>I hate doing this type of stuff, but I feel like this idea is so important it\u2019d be foolish of me not to try. Even if this Kickstarter ends up being unsuccessful, I won\u2019t be able to live with myself if I didn\u2019t do everything in my power.</p></blockquote>\n\n\n\n<p>We can help him. We have blogs, accounts on Twitter, Micro.blog, Mastodon etc. Take two minutes to review Bokeh\u2019s Kickstarter, back it if you\u2019d like, but please write a short post to help him spread the word. And perhaps directly message a few people you know that could help as well.</p>\n\n\n\n<p>As a community we can all help each other with our audiences \u2013 even if they are tiny. I always try to promote things people are building with my blog and even if I only help move the needle a very small amount \u2013 together perhaps we can make a difference for Tim and Bokeh and for others in our community building things and putting them out into the world.</p>", "text": "Timothy Smith, on trying to promote his Kickstarter for Bokeh:\n\n\n\nI hate doing this type of stuff, but I feel like this idea is so important it\u2019d be foolish of me not to try. Even if this Kickstarter ends up being unsuccessful, I won\u2019t be able to live with myself if I didn\u2019t do everything in my power.\n\n\n\nWe can help him. We have blogs, accounts on Twitter, Micro.blog, Mastodon etc. Take two minutes to review Bokeh’s Kickstarter, back it if you’d like, but please write a short post to help him spread the word. And perhaps directly message a few people you know that could help as well.\n\n\n\nAs a community we can all help each other with our audiences – even if they are tiny. I always try to promote things people are building with my blog and even if I only help move the needle a very small amount – together perhaps we can make a difference for Tim and Bokeh and for others in our community building things and putting them out into the world." }, "published": "2019-05-08T09:27:45-04:00", "updated": "2019-05-08T09:27:47-04:00", "category": [ "bokeh", "indieweb", "kickstarter", "photography", "timothy smith" ], "post-type": "article", "_id": "3362477", "_source": "236", "_is_read": true }
{ "type": "entry", "published": "2019-05-08T14:22:19Z", "url": "https://adactio.com/journal/15122", "category": [ "serviceworkers", "javascript", "frontend", "development", "liefi", "goingoffline", "code", "performance", "timeout" ], "name": "Timing out", "content": { "text": "Service workers are great for creating a good user experience when someone is offline. Heck, the book I wrote about service workers is literally called Going Offline.\n\nBut in some ways, the offline experience is relatively easy to handle. It\u2019s a binary situation; either you\u2019re online or you\u2019re offline. What\u2019s more challenging\u2014and probably more common\u2014is the situation that Jake calls Lie-Fi. That\u2019s when technically you\u2019ve got a network connection \u2026but it\u2019s a shitty connection, like one bar of mobile signal. In that situation, because there\u2019s technically a connection, the user gets a slow frustrating experience. Whatever code you\u2019ve got in your service worker for handling offline situations will never get triggered. When you\u2019re handling fetch events inside a service worker, there\u2019s no automatic time-out.\n\nBut you can make one.\n\nThat\u2019s what I\u2019ve done recently here on adactio.com. Before showing you what I added to my service worker script to make that happen, let me walk you through my existing strategy for handling offline situations.\n\nService worker strategies\n\nAlright, so in my service worker script, I\u2019ve got a block of code for handling requests from fetch events:\n\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n // Do something with this request.\n});\n\nI\u2019ve got two strategies in my code. One is for dealing with requests for pages:\n\nif (request.headers.get('Accept').includes('text/html')) {\n // Code for handling page requests.\n}\n\nBy adding an else clause I can have a different strategy for dealing with requests for anything else\u2014images, style sheets, scripts, and so on:\n\nif (request.headers.get('Accept').includes('text/html')) {\n // Code for handling page requests.\n} else {\n // Code for handling everthing else.\n}\n\nFor page requests, I\u2019m going to try to go the network first:\n\nfetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })\n\nMy logic is:\n\n\nWhen someone requests a page, try to fetch it from the network.\n\n\nIf that doesn\u2019t work, we\u2019re in an offline situation. That triggers the catch clause. That\u2019s where I have my offline strategy: show a custom offline page that I\u2019ve previously cached (during the install event):\n\n.catch( fetchError => {\n return caches.match('/offline');\n})\n\nNow my logic has been expanded to this:\n\n\nWhen someone requests a page, try to fetch it from the network, but if that doesn\u2019t work, show a custom offline page instead.\n\n\nSo my overall code for dealing with requests for pages looks like this:\n\nif (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n}\n\nNow I can fill in the else statement that handles everything else\u2014images, style sheets, scripts, and so on. Here my strategy is different. I\u2019m looking in my caches first, and I only fetch the file from network if the file can\u2019t be found in any cache:\n\ncaches.match(request)\n.then( responseFromCache => {\n return responseFromCache || fetch(request);\n})\n\nHere\u2019s all that fetch-handling code put together:\n\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});\n\nGood.\n\nCache as you go\n\nNow I want to introduce an extra step in the part of the code where I deal with requests for pages. Whenever I fetch a page from the network, I\u2019m going to take the opportunity to squirrel it away in a cache. I\u2019m calling that cache \u201cpages\u201d. I\u2019m imaginative like that.\n\nfetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n return responseFromFetch;\n })\n\nYou\u2019ll notice that I can\u2019t put the response itself (responseFromCache) into the cache. That\u2019s a stream that I only get to use once. Instead I need to make a copy:\n\nconst copy = responseFromFetch.clone();\n\nThat\u2019s what gets put in the pages cache:\n\nfetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n)\n\nNow my logic for page requests has an extra piece to it:\n\n\nWhen someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, show a custom offline page instead.\n\n\nHere\u2019s my updated fetch-handling code:\n\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});\n\nI call this the cache-as-you-go pattern. The more pages someone views on my site, the more pages they\u2019ll have cached.\n\nNow that there\u2019s an ever-growing cache of previously visited pages, I can update my offline fallback. Currently, I reach straight for the custom offline page:\n\n.catch( fetchError => {\n return caches.match('/offline');\n})\n\nBut now I can try looking for a cached copy of the requested page first:\n\n.catch( fetchError => {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || caches.match('/offline');\n })\n});\n\nNow my offline logic is expanded:\n\n\nWhen someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, first look for an existing copy in a cache, and otherwise show a custom offline page instead.\n\n\nI can also access this ever-growing cache of pages from my custom offline page to show people which pages they can revisit, even if there\u2019s no internet connection.\n\nSo far, so good. Everything I\u2019ve outlined so far is a good robust strategy for handling offline situations. Now I\u2019m going to deal with the lie-fi situation, and it\u2019s that cache-as-you-go strategy that sets me up nicely.\n\nTiming out\n\nI want to throw this addition into my logic:\n\n\nWhen someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, first look for an existing copy in a cache, and otherwise show a custom offline page instead (but if the request is taking too long, try to show a cached version of the page).\n\n\nThe first thing I\u2019m going to do is rewrite my code a bit. If the fetch event is for a page, I\u2019m going to respond with a promise:\n\nif (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n // Code for handling page requests.\n })\n );\n}\n\nPromises are kind of weird things to get your head around. They\u2019re tailor-made for doing things asynchronously. You can set up two parameters; a success condition and a failure condition. If the success condition is executed, then we say the promise has resolved. If the failure condition is executed, then the promise rejects.\n\nIn my re-written code, I\u2019m calling the success condition resolveWithResponse (and I haven\u2019t bothered with a failure condition, tsk, tsk). I\u2019m going to use resolveWithResponse in my promise everywhere that I used to have a return statement:\n\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n fetch(request)\n .then( responseFromFetch => {\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n resolveWithResponse(responseFromFetch);\n })\n .catch( fetchError => {\n caches.match(request)\n .then( responseFromCache => {\n resolveWithResponse(\n responseFromCache || caches.match('/offline')\n );\n })\n })\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});\n\nBy itself, rewriting my code as a promise doesn\u2019t change anything. Everything\u2019s working the same as it did before. But now I can introduce the time-out logic. I\u2019m going to put this inside my promise:\n\nconst timer = setTimeout( () => {\n caches.match(request)\n .then( responseFromCache => {\n if (responseFromCache) {\n resolveWithResponse(responseFromCache);\n }\n })\n}, 3000);\n\nIf a request takes three seconds (3000 milliseconds), then that code will execute. At that point, the promise attempts to resolve with a response from the cache instead of waiting for the network. If there is a cached response, that\u2019s what the user now gets. If there isn\u2019t, then the wait continues for the network.\n\nThe last thing left for me to do is cancel the countdown to timing out if a network response does return within three seconds. So I put this in the then clause that\u2019s triggered by a successful network response:\n\nclearTimeout(timer);\n\nI also add the clearTimeout statement to the catch clause that handles offline situations. Here\u2019s the final code:\n\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n const timer = setTimeout( () => {\n caches.match(request)\n .then( responseFromCache => {\n if (responseFromCache) {\n resolveWithResponse(responseFromCache);\n }\n })\n }, 3000);\n fetch(request)\n .then( responseFromFetch => {\n clearTimeout(timer);\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n resolveWithResponse(responseFromFetch);\n })\n .catch( fetchError => {\n clearTimeout(timer);\n caches.match(request)\n .then( responseFromCache => {\n resolveWithResponse(\n responseFromCache || caches.match('/offline')\n );\n })\n })\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request)\n })\n }\n});\n\nThat\u2019s the JavaScript translation of this logic:\n\n\nWhen someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, first look for an existing copy in a cache, and otherwise show a custom offline page instead (but if the request is taking too long, try to show a cached version of the page).\n\nFor everything else, try finding a cached version first, otherwise fetch it from the network.\n\n\nPros and cons\n\nAs with all service worker enhancements to a website, this strategy will do absolutely nothing for first-time visitors. If you\u2019ve never visited my site before, you\u2019ve got nothing cached. But the more you return to the site, the more your cache is primed for speedy retrieval.\n\nI think that serving up a cached copy of a page when the network connection is flaky is a pretty good strategy \u2026most of the time. If we\u2019re talking about a blog post on this site, then sure, there won\u2019t be much that the reader is missing out on\u2014a fixed typo or ten; maybe some additional webmentions at the end of a post. But if we\u2019re talking about the home page, then a reader with a flaky network connection might think there\u2019s nothing new to read when they\u2019re served up a stale version.\n\nWhat I\u2019d really like is some way to know\u2014on the client side\u2014whether or not the currently-loaded page came from a cache or from a network. Then I could add some kind of interface element that says, \"Hey, this page might be stale\u2014click here if you want to check for a fresher version.\" I\u2019d also need some way in the service worker to identify any requests originating from that interface element and make sure they always go out to the network.\n\nI think that should be doable somehow. If you can think of a way to do it, please share it. Write a blog post and send me the link.\n\nBut even without the option to over-ride the time-out, I\u2019m glad that I\u2019m at least doing something to handle the lie-fi situation. Perhaps I should write a sequel to Going Offline called Still Online But Only In Theory Because The Connection Sucks.", "html": "<p>Service workers are great for creating a good user experience when someone is offline. Heck, the book I wrote about service workers is literally called <a href=\"https://abookapart.com/products/going-offline\">Going Offline</a>.</p>\n\n<p>But in some ways, the offline experience is relatively easy to handle. It\u2019s a binary situation; either you\u2019re online or you\u2019re offline. What\u2019s more challenging\u2014and probably more common\u2014is the situation that <a href=\"https://jakearchibald.com/\">Jake</a> calls <a href=\"https://www.urbandictionary.com/define.php?term=lie-fi\">Lie-Fi</a>. That\u2019s when technically you\u2019ve got a network connection \u2026but it\u2019s a shitty connection, like one bar of mobile signal. In that situation, because there\u2019s <em>technically</em> a connection, the user gets a slow frustrating experience. Whatever code you\u2019ve got in your service worker for handling offline situations will never get triggered. When you\u2019re handling <code>fetch</code> events inside a service worker, there\u2019s no automatic time-out.</p>\n\n<p>But you can make one.</p>\n\n<p>That\u2019s what I\u2019ve done recently here on <a href=\"https://adactio.com/\">adactio.com</a>. Before showing you what I <em>added</em> to my service worker script to make that happen, let me walk you through my existing strategy for handling offline situations.</p>\n\n<h3>Service worker strategies</h3>\n\n<p>Alright, so in <a href=\"https://adactio.com/serviceworker.js\">my service worker script</a>, I\u2019ve got a block of code for handling requests from <code>fetch</code> events:</p>\n\n<pre><code>addEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n // Do something with this request.\n});</code></pre>\n\n<p>I\u2019ve got two strategies in my code. One is for dealing with requests for <em>pages</em>:</p>\n\n<pre><code>if (request.headers.get('Accept').includes('text/html')) {\n // Code for handling page requests.\n}</code></pre>\n\n<p>By adding an <code>else</code> clause I can have a different strategy for dealing with requests for anything else\u2014images, style sheets, scripts, and so on:</p>\n\n<pre><code>if (request.headers.get('Accept').includes('text/html')) {\n // Code for handling page requests.\n} else {\n // Code for handling everthing else.\n}</code></pre>\n\n<p>For page requests, I\u2019m going to try to go the network first:</p>\n\n<pre><code>fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })</code></pre>\n\n<p>My logic is:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network.</p>\n</blockquote>\n\n<p>If that doesn\u2019t work, we\u2019re in an offline situation. That triggers the <code>catch</code> clause. That\u2019s where I have my offline strategy: show a custom offline page that I\u2019ve previously cached (during the <code>install</code> event):</p>\n\n<pre><code>.catch( fetchError => {\n return caches.match('/offline');\n})</code></pre>\n\n<p>Now my logic has been expanded to this:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network, <strong>but if that doesn\u2019t work, show a custom offline page instead</strong>.</p>\n</blockquote>\n\n<p>So my overall code for dealing with requests for pages looks like this:</p>\n\n<pre><code>if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n}</code></pre>\n\n<p>Now I can fill in the <code>else</code> statement that handles everything else\u2014images, style sheets, scripts, and so on. Here my strategy is different. I\u2019m looking in my caches <em>first</em>, and I only fetch the file from network if the file can\u2019t be found in any cache:</p>\n\n<pre><code>caches.match(request)\n.then( responseFromCache => {\n return responseFromCache || fetch(request);\n})</code></pre>\n\n<p>Here\u2019s all that fetch-handling code put together:</p>\n\n<pre><code>addEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});</code></pre>\n\n<p>Good.</p>\n\n<h3>Cache as you go</h3>\n\n<p>Now I want to introduce an extra step in the part of the code where I deal with requests for pages. Whenever I fetch a page from the network, I\u2019m going to take the opportunity to squirrel it away in a cache. I\u2019m calling that cache \u201c<code>pages</code>\u201d. I\u2019m imaginative like that.</p>\n\n<pre><code>fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n return responseFromFetch;\n })</code></pre>\n\n<p>You\u2019ll notice that I can\u2019t put the response itself (<code>responseFromCache</code>) into the cache. That\u2019s a stream that I only get to use once. Instead I need to make a copy:</p>\n\n<pre><code>const copy = responseFromFetch.clone();</code></pre>\n\n<p><em>That\u2019s</em> what gets put in the <code>pages</code> cache:</p>\n\n<pre><code>fetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n)</code></pre>\n\n<p>Now my logic for page requests has an extra piece to it:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network <strong>and store a copy in a cache</strong>, but if that doesn\u2019t work, show a custom offline page instead.</p>\n</blockquote>\n\n<p>Here\u2019s my updated <code>fetch</code>-handling code:</p>\n\n<pre><code>addEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n fetch(request)\n .then( responseFromFetch => {\n <b>const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n .then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }</b>\n return responseFromFetch;\n })\n .catch( fetchError => {\n return caches.match('/offline');\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});</code></pre>\n\n<p>I call this the cache-as-you-go pattern. The more pages someone views on my site, the more pages they\u2019ll have cached.</p>\n\n<p>Now that there\u2019s an ever-growing cache of previously visited pages, I can update my offline fallback. Currently, I reach straight for the custom offline page:</p>\n\n<pre><code>.catch( fetchError => {\n return caches.match('/offline');\n})</code></pre>\n\n<p>But now I can try looking for a cached copy of the requested page first:</p>\n\n<pre><code>.catch( fetchError => {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || caches.match('/offline');\n })\n});</code></pre>\n\n<p>Now my offline logic is expanded:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, <strong>first look for an existing copy in a cache</strong>, and otherwise show a custom offline page instead.</p>\n</blockquote>\n\n<p>I can also access this ever-growing cache of pages from <a href=\"https://adactio.com/offline\">my custom offline page</a> to show people which pages they can revisit, even if there\u2019s no internet connection.</p>\n\n<p>So far, so good. Everything I\u2019ve outlined so far is a good robust strategy for handling offline situations. Now I\u2019m going to deal with the lie-fi situation, and it\u2019s that cache-as-you-go strategy that sets me up nicely.</p>\n\n<h3>Timing out</h3>\n\n<p>I want to throw this addition into my logic:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, first look for an existing copy in a cache, and otherwise show a custom offline page instead <strong>(but if the request is taking too long, try to show a cached version of the page)</strong>.</p>\n</blockquote>\n\n<p>The first thing I\u2019m going to do is rewrite my code a bit. If the <code>fetch</code> event is for a page, I\u2019m going to respond with a promise:</p>\n\n<pre><code>if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n // Code for handling page requests.\n })\n );\n}</code></pre>\n\n<p>Promises are kind of weird things to get your head around. They\u2019re tailor-made for doing things asynchronously. You can set up two parameters; a success condition and a failure condition. If the success condition is executed, then we say the promise has <em>resolved</em>. If the failure condition is executed, then the promise <em>rejects</em>.</p>\n\n<p>In my re-written code, I\u2019m calling the success condition <code>resolveWithResponse</code> (and I haven\u2019t bothered with a failure condition, tsk, tsk). I\u2019m going to use <code>resolveWithResponse</code> in my promise everywhere that I used to have a <code>return</code> statement:</p>\n\n<pre><code>addEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n fetch(request)\n .then( responseFromFetch => {\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n <b>resolveWithResponse(responseFromFetch);</b>\n })\n .catch( fetchError => {\n caches.match(request)\n .then( responseFromCache => {\n <b>resolveWithResponse(\n responseFromCache || caches.match('/offline')\n );</b>\n })\n })\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request);\n })\n }\n});</code></pre>\n\n<p>By itself, rewriting my code as a promise doesn\u2019t change anything. Everything\u2019s working the same as it did before. But now I can introduce the time-out logic. I\u2019m going to put this inside my promise:</p>\n\n<pre><code>const timer = setTimeout( () => {\n caches.match(request)\n .then( responseFromCache => {\n if (responseFromCache) {\n resolveWithResponse(responseFromCache);\n }\n })\n}, 3000);</code></pre>\n\n<p>If a request takes three seconds (3000 milliseconds), then that code will execute. At that point, the promise attempts to resolve with a response from the cache instead of waiting for the network. If there is a cached response, that\u2019s what the user now gets. If there isn\u2019t, then the wait continues for the network.</p>\n\n<p>The last thing left for me to do is cancel the countdown to timing out if a network response <em>does</em> return within three seconds. So I put this in the <code>then</code> clause that\u2019s triggered by a successful network response:</p>\n\n<pre><code>clearTimeout(timer);</code></pre>\n\n<p>I also add the <code>clearTimeout</code> statement to the <code>catch</code> clause that handles offline situations. Here\u2019s the final code:</p>\n\n<pre><code>addEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n if (request.headers.get('Accept').includes('text/html')) {\n fetchEvent.respondWith(\n new Promise( resolveWithResponse => {\n <b>const timer = setTimeout( () => {\n caches.match(request)\n .then( responseFromCache => {\n if (responseFromCache) {\n resolveWithResponse(responseFromCache);\n }\n })\n }, 3000);</b>\n fetch(request)\n .then( responseFromFetch => {\n <b>clearTimeout(timer);</b>\n const copy = responseFromFetch.clone();\n try {\n fetchEvent.waitUntil(\n caches.open('pages')\n then( pagesCache => {\n pagesCache.put(request, copy);\n })\n )\n } catch(error) {\n console.error(error);\n }\n resolveWithResponse(responseFromFetch);\n })\n .catch( fetchError => {\n <b>clearTimeout(timer);</b>\n caches.match(request)\n .then( responseFromCache => {\n resolveWithResponse(\n responseFromCache || caches.match('/offline')\n );\n })\n })\n })\n );\n } else {\n caches.match(request)\n .then( responseFromCache => {\n return responseFromCache || fetch(request)\n })\n }\n});</code></pre>\n\n<p>That\u2019s the JavaScript translation of this logic:</p>\n\n<blockquote>\n<p>When someone requests a page, try to fetch it from the network and store a copy in a cache, but if that doesn\u2019t work, first look for an existing copy in a cache, and otherwise show a custom offline page instead (but if the request is taking too long, try to show a cached version of the page).</p>\n\n<p>For everything else, try finding a cached version first, otherwise fetch it from the network.</p>\n</blockquote>\n\n<h3>Pros and cons</h3>\n\n<p>As with all service worker enhancements to a website, this strategy will do absolutely nothing for first-time visitors. If you\u2019ve never visited my site before, you\u2019ve got nothing cached. But the more you return to the site, the more your cache is primed for speedy retrieval.</p>\n\n<p>I think that serving up a cached copy of a page when the network connection is flaky is a pretty good strategy \u2026most of the time. If we\u2019re talking about a blog post on this site, then sure, there won\u2019t be much that the reader is missing out on\u2014a fixed typo or ten; maybe some additional webmentions at the end of a post. But if we\u2019re talking about the home page, then a reader with a flaky network connection might think there\u2019s nothing new to read when they\u2019re served up a stale version.</p>\n\n<p>What I\u2019d <em>really</em> like is some way to know\u2014on the client side\u2014whether or not the currently-loaded page came from a cache or from a network. Then I could add some kind of interface element that says, \"Hey, this page might be stale\u2014click here if you want to check for a fresher version.\" I\u2019d also need some way in the service worker to identify any requests originating from that interface element and make sure they <em>always</em> go out to the network.</p>\n\n<p>I think that should be doable somehow. If you can think of a way to do it, please share it. Write a blog post and <a href=\"https://adactio.com/contact\">send me the link</a>.</p>\n\n<p>But even without the option to over-ride the time-out, I\u2019m glad that I\u2019m at least doing <em>something</em> to handle the lie-fi situation. Perhaps I should write a sequel to <a href=\"https://abookapart.com/products/going-offline\">Going Offline</a> called Still Online But Only In Theory Because The Connection Sucks.</p>" }, "author": { "type": "card", "name": "Jeremy Keith", "url": "https://adactio.com/", "photo": "https://aperture-proxy.p3k.io/bbbacdf0a064621004f2ce9026a1202a5f3433e0/68747470733a2f2f6164616374696f2e636f6d2f696d616765732f70686f746f2d3135302e6a7067" }, "post-type": "note", "_id": "3361482", "_source": "2", "_is_read": true }
{ "type": "entry", "published": "2019-05-07 17:45-0700", "url": "http://tantek.com/2019/127/t1/indiewebcamp-berlin-built-theme-switcher", "category": [ "IndieWebCamp", "Berlin", "indieweb" ], "content": { "text": "During #IndieWebCamp #Berlin I built a simple theme switcher for my site!\nhyperlinks -> URL query param -> PHP to add class to <body> & query param to local links -> CSS class selectors -> CSS variables -> colors & font. No cookies, no JS. #indieweb", "html": "During #<span class=\"p-category\">IndieWebCamp</span> #<span class=\"p-category\">Berlin</span> I built a simple theme switcher for my site!<br />hyperlinks -> URL query param -> PHP to add class to <body> & query param to local links -> CSS class selectors -> CSS variables -> colors & font. No cookies, no JS. #<span class=\"p-category\">indieweb</span>" }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "note", "_id": "3355053", "_source": "1", "_is_read": true }
Fixed an issue in the new Micro.blog themes for IndieWeb-related tags and custom CSS. The great thing about all these themes is that they are completely customizable. Very powerful. But with great power comes… great ability for me to forget important HTML tags.
{ "type": "entry", "author": { "name": "Manton Reece", "url": "https://www.manton.org/", "photo": "https://aperture-proxy.p3k.io/907926e361383204bd1bc913c143c23e70ae69bb/68747470733a2f2f6d6963726f2e626c6f672f6d616e746f6e2f6176617461722e6a7067" }, "url": "https://www.manton.org/2019/05/07/fixed-an-issue.html", "content": { "html": "<p>Fixed an issue in the new Micro.blog themes for IndieWeb-related tags and custom CSS. The great thing about all these themes is that they are <em>completely</em> customizable. Very powerful. But with great power comes\u2026 great ability for me to forget important HTML tags.</p>", "text": "Fixed an issue in the new Micro.blog themes for IndieWeb-related tags and custom CSS. The great thing about all these themes is that they are completely customizable. Very powerful. But with great power comes\u2026 great ability for me to forget important HTML tags." }, "published": "2019-05-07T14:51:32-05:00", "post-type": "note", "_id": "3349976", "_source": "12", "_is_read": true }
{ "type": "entry", "published": "2019-05-07T14:38:32+10:00", "url": "https://unicyclic.com/mal/2019-05-07-On_planets_and_reading_lists", "category": [ "https://news.indieweb.org/en" ], "syndication": [ "https://twitter.com/malcolmblaney/status/1125620969261928449" ], "name": "On planets and reading lists", "content": { "text": "This is going to be a long one, so the short version is summed up in this screenshot:\n\n\n\n\nThat's from the top of this page: unicyclic.com/indieweb, which is a feed combined from different sources, commonly referred to as a planet. Up until now I've been adding new feeds to that page as people join the IndieWeb community, but I've now automated that process using follow webmentions.\n\n\nWhat is a follow webmention? Well you start by writing a post on your own website containing a link to someone you've started following in your reader, with an extra bit of microformats in the markup of the link: class=\"u-follow-of\". Then you would send webmentions for the post, so that the recipient can check your content and discover that you have indeed started following them.\n\n\nThat is what the indieweb account on unicyclic.com is now looking for, but with one extra step. When it receives a follow webmention, it will follow you back by adding you to the planet it manages. It does this by looking at the author of the post, and then doing feed discovery based on that URL. If it all works out you will be notified in the response to your webmention.\n\n\nIf you don't want to be listed in the planet you can unfollow the indieweb account too, no hard feelings! This is done by removing your follow post and re-sending webmentions, which should result in a 410 Gone status code from your site.\n\n\nSo that's how this planet now works, but what is really fun is connecting this to reading lists. I'm not sure what the right terminology is here... reading lists are also known as subscriptions lists, or dynamic OPML files. Whatever they are Dobrado now supports them, so you can subscribe to unicyclic.com/indieweb and stay up to date with the feeds of whoever happens to have joined.\n\n\nBoth OPML and microformats versions are available to subscribe to and are linked from that page for discovery. Since microformats is just HTML it is also a nice web page to browse, and adds to the growing list of directories in a year that is widely regarded as the year of the indieweb directory. If you parse the microformats on that page you will notice the reading list is an h-feed of h-cards. Whichever version you subscribe to, if your reader supports this type of subscription it should add feeds to your reader when they are added to the list, and remove the feed when they are taken off.\n\n\nWhen thinking about implementing this I realised I didn't always want to stop following people just because they were removed from a reading list, so I added an extra option to manually add feeds that you're automatically subscribed to. Dobrado now provides a dialog that looks like this when viewing a reading list:\n\n\n\n\nEvery feed allows setting a channel, the new bit here is the description at the bottom of the dialog that mentions manually adding the feeds below. Scrolling down allows you to go through the feeds you've been subscribed to and manually add them, which just means they won't be removed from your reader if they are removed from the reading list or if you unsubscribe from that list completely. If you're already following a feed that just happens to be on a reading list you subscribe to, this also means your original subscription will be kept.\n\n\nUp until now I've been reading feeds from some indieweb members in my own reader, and then also visiting the indieweb page to check out the rest, which of course meant reading things twice! Pretty happy that I can now just set a channel for it and also provide a version for others to check out or subscribe to themselves.", "html": "This is going to be a long one, so the short version is summed up in this screenshot:<br /><br /><img alt=\"\" src=\"https://aperture-proxy.p3k.io/4474127354a9495ab68e2b2a43e3b8674b8b5d37/68747470733a2f2f756e696379636c69632e636f6d2f6d616c2f7075626c69632f706c616e6574312e706e67\" /><br /><br />\nThat's from the top of this page: <a href=\"https://unicyclic.com/indieweb\">unicyclic.com/indieweb</a>, which is a feed combined from different sources, commonly referred to as a <em>planet</em>. Up until now I've been adding new feeds to that page as people join the <a href=\"https://indieweb.org\">IndieWeb community</a>, but I've now automated that process using <em>follow webmentions</em>.<br /><br />\nWhat is a follow webmention? Well you start by writing a post on your own website containing a link to someone you've started following in your reader, with an extra bit of microformats in the markup of the link: <strong>class=\"u-follow-of\"</strong>. Then you would send webmentions for the post, so that the recipient can check your content and discover that you have indeed started following them.<br /><br />\nThat is what the indieweb account on <a href=\"https://unicyclic.com\">unicyclic.com</a> is now looking for, but with one extra step. When it receives a follow webmention, it will follow you back by adding you to the planet it manages. It does this by looking at the author of the post, and then doing feed discovery based on that URL. If it all works out you will be notified in the response to your webmention.<br /><br />\nIf you don't want to be listed in the planet you can unfollow the indieweb account too, no hard feelings! This is done by removing your follow post and re-sending webmentions, which should result in a <strong>410 Gone</strong> status code from your site.<br /><br />\nSo that's how this planet now works, but what is really fun is connecting this to <em>reading lists</em>. I'm not sure what the right terminology is here... reading lists are also known as subscriptions lists, or dynamic OPML files. Whatever they are <a href=\"https://dobrado.net\">Dobrado</a> now supports them, so you can subscribe to <a href=\"https://unicyclic.com/indieweb\">unicyclic.com/indieweb</a> and stay up to date with the feeds of whoever happens to have joined.<br /><br />\nBoth OPML and microformats versions are available to subscribe to and are linked from that page for discovery. Since microformats is just HTML it is also <a href=\"https://unicyclic.com/indieweb/directory\">a nice web page to browse</a>, and adds to the growing list of directories in a year that is widely regarded as <em>the year of the indieweb directory</em>. If you parse the microformats on that page you will notice the reading list is an <strong>h-feed</strong> of <strong>h-cards</strong>. Whichever version you subscribe to, if your reader supports this type of subscription it should add feeds to your reader when they are added to the list, and remove the feed when they are taken off.<br /><br />\nWhen thinking about implementing this I realised I didn't always want to stop following people just because they were removed from a reading list, so I added an extra option to manually add feeds that you're automatically subscribed to. Dobrado now provides a dialog that looks like this when viewing a reading list:<br /><br /><img alt=\"\" src=\"https://aperture-proxy.p3k.io/13ea918fb94b5c1b1d53e9dd70619c8f367fe24d/68747470733a2f2f756e696379636c69632e636f6d2f6d616c2f7075626c69632f6368616e6e656c5f6c6973742e706e67\" /><br /><br />\nEvery feed allows setting a channel, the new bit here is the description at the bottom of the dialog that mentions manually adding the feeds below. Scrolling down allows you to go through the feeds you've been subscribed to and manually add them, which just means they won't be removed from your reader if they are removed from the reading list or if you unsubscribe from that list completely. If you're already following a feed that just happens to be on a reading list you subscribe to, this also means your original subscription will be kept.<br /><br />\nUp until now I've been reading feeds from some indieweb members in my own reader, and then also visiting the indieweb page to check out the rest, which of course meant reading things twice! Pretty happy that I can now just set a channel for it and also provide a version for others to check out or subscribe to themselves.<a href=\"https://brid.gy/publish/twitter\"></a><a href=\"https://twitter.com/malcolmblaney/status/1125620969261928449\" class=\"u-syndication\"></a>" }, "author": { "type": "card", "name": "Malcolm Blaney", "url": "https://unicyclic.com/mal", "photo": "https://aperture-proxy.p3k.io/4f46272c0027449ced0d7cf8de31ea1bec37210e/68747470733a2f2f756e696379636c69632e636f6d2f6d616c2f7075626c69632f70726f66696c655f736d616c6c5f7468756d622e706e67" }, "post-type": "article", "_id": "3338713", "_source": "243", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/05/04/5360/", "published": "2019-05-04T23:27:26+00:00", "content": { "html": "<p>Hmm, will definitely give WordPress ActivityPub a try next. Wondering how it will work with posts made via Micropub. Bridgy Fed will work fine, as it\u2019s just technically another syndication target. Given WP AP is by Matthias though I\u2019m pretty sure it\u2019ll play nicely with the other Indieweb plugins. <a href=\"https://wordpress.org/plugins/activitypub/\">wordpress.org/plugins/activitypub/</a></p>\n<p>#IndieWeb</p>\n<p>The post <a href=\"https://doubleloop.net/2019/05/04/5360/\">#5360</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "Hmm, will definitely give WordPress ActivityPub a try next. Wondering how it will work with posts made via Micropub. Bridgy Fed will work fine, as it\u2019s just technically another syndication target. Given WP AP is by Matthias though I\u2019m pretty sure it\u2019ll play nicely with the other Indieweb plugins. wordpress.org/plugins/activitypub/\n#IndieWeb\nThe post #5360 appeared first on doubleloop." }, "name": "#5360", "post-type": "note", "_id": "3309746", "_source": "1895", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/05/04/5357/", "published": "2019-05-04T20:36:17+00:00", "content": { "html": "Liked <a href=\"https://boffosocko.com/2019/05/04/indieweb-book-club-ruined-by-design/\">IndieWeb Book Club: Ruined By Design</a> <em>(BoffoSocko)</em>\n<blockquote>Join an experimental distributed and open web book club to read Mike Monteiro's Ruined by Design.</blockquote>\n\n<p>The post <a href=\"https://doubleloop.net/2019/05/04/5357/\">#5357</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "Liked IndieWeb Book Club: Ruined By Design (BoffoSocko)\nJoin an experimental distributed and open web book club to read Mike Monteiro's Ruined by Design.\n\nThe post #5357 appeared first on doubleloop." }, "name": "#5357", "post-type": "note", "_id": "3308414", "_source": "1895", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/05/04/bridging-the-indieweb-and-the-fediverse-part-2/", "published": "2019-05-04T19:55:12+00:00", "content": { "html": "<p>In part 1, I discussed why you might want to bridge your Indieweb site to the Fediverse.</p>\n<p>In this follow up post, I\u2019ll describe one way of doing it that I\u2019ve been tinkering with recently.</p>\n<p>The tl;dr: using <a href=\"https://indieweb.org/WordPress/Plugins\">WordPress Indieweb plugins</a> and <a href=\"https://fed.brid.gy/\">Bridgy Fed</a>; it works pretty smoothly; still a few quirks at present; it\u2019s awesome and lots of fun to mess around with.</p>\n\n<p><a href=\"https://aperture-proxy.p3k.io/6b6002c477260ffc758cc94153413e15fef678a8/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f6272696467652d616c6c2d7468652d7468696e67732e6a7067\"><img src=\"https://aperture-proxy.p3k.io/6b6002c477260ffc758cc94153413e15fef678a8/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f6272696467652d616c6c2d7468652d7468696e67732e6a7067\" alt=\"\" /></a></p>\n\n<p>Quick preamble (as if the last post wasn\u2019t enough!). Indieweb is chiefly about having your own site. It certainly doesn\u2019t have to be WordPress \u2013 there are a plurality of projects out there, pretty much in every language/framework under the sun. And in fact, just having a single page at your own URL is being part of the Indieweb. All this stuff is just extra sugar on top.</p>\n<p>Additionally, you don\u2019t need Bridgy Fed to wire a WordPress site up to the Fediverse \u2013 you could bypass all the Indieweb plugins and use <a href=\"https://getpterotype.com/\">pterotype</a>, or <a href=\"https://wordpress.org/plugins/activitypub/\">WordPress ActivityPub</a>.</p>\n<p>But that said, I have a WordPress Indieweb site, and I want to use Bridgy Fed, so here I\u2019ll talk about that combination. Ready to shave some yaks? Let\u2019s go!</p>\n<h2>Installing WordPress</h2>\n<p>It\u2019s outside the scope of this article to go through WordPress installation steps, but it\u2019s pretty simple and there\u2019s a million and one resources out there already on how to do so. For the purposes of this blog post, you just need to get to the point of having a fresh WP install.</p>\n<p>There\u2019s various different ways to install your own WordPress:</p>\n<ul><li>you can pay <a href=\"http://Wordpress.com/\">WordPress.com</a> \u2013 I\u2019ve never tried it for an Indieweb site, and I think you need something like \u2018Business Class\u2019 to install any non-Automattic sanctioned plugins such as the Indieweb ones</li>\n<li>you can use a web hosting service \u2013 99.999% of shared hosting providers will have a one click install of WordPress. For example, <a href=\"https://www.gandi.net/en/simple-hosting\">Gandi</a>.</li>\n<li>you can install it on your own server \u2013 I\u2019ve done it here for my testing with a Digital Ocean dedicated <a href=\"https://marketplace.digitalocean.com/apps/wordpress\">WordPress droplet</a>, where you get a virtual private server (VPS) with all the LAMP bits and pieces that you need preconfigured, and WordPress ready to rock. But my main site is a manual WP install on a barebones VPS at <a href=\"https://cloudvault.me/\">cloudvault.me</a>.</li>\n</ul><p>I personally like installing on a VPS as I like to tinker around with other bits and pieces on the server, but it is by no means necessary. Everything in this post should work wherever you have WordPress installed. If you\u2019re new to it, I\u2019d probably recommend using a 1click install on a shared hosting service.</p>\n<h2>Setting up the Indieweb plugins</h2>\n<p>Alright, so let\u2019s assume we have a fresh install of WordPress, all ready to rock.</p>\n<p>Next up for us is to get it indiewebified.</p>\n<h3>Indiewebify.me</h3>\n<p>There\u2019s a fantastic bunch of WordPress plugins that will add all of the Indieweb functionality to our site. For the purposes of our Fediverse bridgying, we don\u2019t need all of them, but we\u2019ll use a fair few. The individual pieces we\u2019ll be needing are: Webmentions; Post Kinds; Syndication Links; Semantic Linkbacks; and WebSub. And we\u2019ll need a theme that supports microformats, for which we\u2019ll go with SemPress.</p>\n<p>But before all that, first off, we\u2019ll install the main Indieweb plugin. This gives us a central place in the WordPress dashboard to manage our other Indieweb plugins, and adds a couple of the Indieweb <a href=\"https://indieweb.org/Category:building-blocks\">building blocks</a> itself.</p>\n<p>Go to <code>Plugins -> Add New</code> and search for <em>Indieweb</em>. Then, install and activate the plugin.</p>\n<p><a href=\"https://aperture-proxy.p3k.io/d612724eda6e3d525f990260935503d267f053e4/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e6469657765622d706c7567696e2d696e7374616c6c2e706e67\"><img src=\"https://aperture-proxy.p3k.io/d612724eda6e3d525f990260935503d267f053e4/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e6469657765622d706c7567696e2d696e7374616c6c2e706e67\" alt=\"\" /></a></p>\n<p>Once activated, you\u2019ll get a new Indieweb section in your dashboard sidebar:</p>\n<a href=\"https://aperture-proxy.p3k.io/9f216d111494c0578316eb882a32b0ff83d7dc05/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e6469657765622d736964656261722e706e67\"><img src=\"https://aperture-proxy.p3k.io/9f216d111494c0578316eb882a32b0ff83d7dc05/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e6469657765622d736964656261722e706e67\" alt=\"\" /></a>\n<p>Go to <strong>Getting Started</strong> and have a read through \u2013 it gives some nice general information on getting started with Indieweb in WordPress. We will have a good read of that, won\u2019t we, and then we\u2019ll start to activate the relevant subplugins for our purposes today.</p>\n<h3>Plug me in</h3>\n<p>In the dashboard sidebar, go to <strong>Indieweb / Extensions</strong>. This gives us a nice little one stop shop to install Indieweb related plugins.</p>\n<a href=\"https://doubleloop.net/wp-content/uploads/2019/05/indieweb-extensions.png\"><img src=\"https://aperture-proxy.p3k.io/7073e67e04bf78ed778828c6d69d85e5315fa473/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e6469657765622d657874656e73696f6e732d31303234783530302e706e67\" alt=\"\" /></a>\n<p>We\u2019ll just install and activate the Indieweb plugins that we need for our fedibridge right now. For each one described below, hit \u2018Install Now\u2019 and then \u2018Activate\u2019.</p>\n<h4>Post Kinds</h4>\n<p>Post Kinds helps us to publish different socialmedia-y microbloggy types of posts on our WordPress site. So this is things like notes, photos, likes, replies, reposts, RSVPs to events, that kind of thing. We could do it all without Post Kinds if we wanted, but Post Kinds helps us think about the various bits of meta-info we might need on different types of posts. And it gives us a little assist in some of the markup that is needed once we start sending notification of these posts to other people and places.</p>\n<h4>Webmention</h4>\n<p>OK, say we\u2019ve posted something to our site. If it\u2019s supposed to be interacting with someone else, how does that get to them?</p>\n<p>As mentioned in the last post, Webmentions are the server-to-server (or you could just think site-to-site) bits of Indieweb communication. When you do something on your site that is an interaction with someone else (e.g. mentioning them, liking one of their posts, etc), you\u2019ll send them a webmention. It crosses the intertubes and delivers a fresh little bit of indielove straight into their website.</p>\n<p>The Webmention plugin also deals with your site <em>receiving</em> webmentions from other people. People like something of yours from their site \u2013 you get notified.</p>\n<p>Quick bit of config for webmentions: some of the webmentions you receive might be an action tied to a specific post of yours \u2013 someone liked it, or someone replied to it. But othertimes it might be that someone wrote a note and just mentioned you in it, it\u2019s not in response to something in particular. For this we can set up a generic mentions page which is a bucket for all those non-post-specific mentions to go into.</p>\n<p>So create a WordPress page called, for example, \u2018Mentions\u2019. Then, go to <code>Indieweb -> Webmentions</code> and change the section <strong>Webmention support for pages</strong>. Yes, we want them, and we also want to choose our newly created page for generic webmentions to go to.</p>\n<a href=\"https://aperture-proxy.p3k.io/853d56140aa9beed30ca9b6b4cc9993b301ad92b/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d67656e657269632d7765626d656e74696f6e732e706e67\"><img src=\"https://aperture-proxy.p3k.io/853d56140aa9beed30ca9b6b4cc9993b301ad92b/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d67656e657269632d7765626d656e74696f6e732e706e67\" alt=\"\" /></a>\n<h4>Semantic Linkbacks</h4>\n<p>Speaking of receiving webmentions\u2026 they come back to us as WordPress comments. The Semantic Linkbacks plugin gives us an assist in formatting those comments a bit better.</p>\n<h4>Syndication Links</h4>\n<p>OK so so far we\u2019re posting posts, and then sending notifications to any Indieweb sites that we interact with. We\u2019re even receiving things back from other sites. But what if we want to also send these posts to an account on a platform somewhere else \u2013 for example, Twitter? Well that\u2019s called syndication, and part of the general principle of <a href=\"https://indieweb.org/POSSE\">POSSEing</a> \u2013 publish on your own site, syndicate elsewhere. Syndication Links helps us with that.</p>\n<p>The same plugin also helps us send stuff to Bridgy Fed, to forward on to the Fediverse \u2013 but note that despite this plugin helping us out here, using Bridgy Fed isn\u2019t really <em>syndication</em>, as we don\u2019t have a Fediverse account somewhere else that we\u2019re sending to \u2013 our WordPress site <em>is</em> the account/actor on the Fediverse.</p>\n<h4>WebSub</h4>\n<p>I\u2019ll be completely honest, I\u2019m not 100% where the WebSub plugin fits into our setup here, but as stated by Bridgy Fed:</p>\n<blockquote><p>If you want people on fedsocnets to see your posts, your site will also need to support WebSub (n\u00e9e PubSubHubbub). Specifically, your Atom feed needs to advertise it.</p></blockquote>\n<p>WebSub in general provides a way for online content to be distributed via hubs, with subscribers subscribing to notifications of updates from publishers publishing to the hub. I kind of thought Bridgy Fed was already being a hub of sorts for us, where we publish via webmention and it notifies Fediverse subscribers via ActivityPub. So I\u2019m not sure what the extra hub setup does. It might be that Bridgy Fed is dealing with direct interactions, and WebSub is dealing with subscriptions to our feed of content. Not sure \u2013 I plan at some point to take a deeper read into <a href=\"https://snarfed.org/indieweb-activitypub-bridge\">how everything works</a> (and hopefully to write about it too) \u2013 but for now let\u2019s just focus on setting it up!</p>\n<h4>Microformats</h4>\n<p>One final thing \u2013 microformats. Microformats are a way of marking up your HTML with a little bit of extra data that makes it more amenable to machine reading. This is useful for another application to e.g. figure out who\u2019s the author of a post, or the owner of a site, or for knowing what a \u2018like\u2019 post is actually liking. It\u2019s an inline format, as opposed to something like RSS or Atom feeds, which are contained in <a href=\"https://indieweb.org/feed_file\">separate files</a>. Bridgy Fed will look at your microformats when you send it a webmention about something on your site \u2013 it\u2019ll come and inspect that post to figure out some of the meta data.</p>\n<p>Two ways to get microformats on your site are:</p>\n<ul><li>install and use the <a href=\"https://wordpress.org/themes/sempress/\">SemPress</a> theme, which has microformats support out of the box</li>\n<li>install the Microformats 2 plugin from the Indieweb Extensions gallery, which will try its best to mark up an existing theme with microformats</li>\n</ul><p>I\u2019ve only ever used SemPress or customisations of it, so can\u2019t speak to the efficacy of the Microformats 2 plugin.</p>\n<h4>h-cards: Hi, my name is</h4>\n<p>One special microformat in particular is the <a href=\"https://indieweb.org/h-card\">h-card</a> format. This is a way of stating who the owner of the site is (and who the author of a post is).</p>\n<p>The Indieweb plugin provides a WordPress widget for h-cards that you can add in to a sidebar. You\u2019ll find it in <code>Appearance -> Widgets</code>, and it\u2019s called <code>Author Profile H-Card</code>. It will take your details out of your user profile in WordPress, and will both display these details wherever you put your widget, and mark them up in h-card format for machine parsing.</p>\n\n<p>Alrighty then! That\u2019s it, plugin wise. Well \u2013 for now. Let\u2019s not forget about the remaining plugins. Micropub and IndieAuth are key parts of a fulsome Indieweb setup, allowing for the client-to-server communication I mentioned previously. It\u2019s super cool stuff, allowing you to post to your site from multiple 3rd party clients. Definitely worth setting up \u2013 but we don\u2019t need it for the purposes of this article, as we can just create posts in the WordPress interface for now.</p>\n<p>(Last but not least: the Simple Location plugin helps you out with doing check-in posts.)</p>\n<h3>Bridgy Fed configuration</h3>\n<p>Let\u2019s take it to the bridgy! Everything up until this point is all stuff that is generally applicable to a WordPress Indieweb site. (Hence why it\u2019s all been in the Indieweb dashboard section so far). There\u2019s a few extra bits of config we need to do specifically for Bridgy Fed that haven\u2019t made it into the Indieweb dashboard just yet.</p>\n<h4>WebSub hub</h4>\n<p>One extra thing we need to do with the WebSub plugin is change the WebSub hub that we\u2019re pointing. We can do that in <code>Options -> WebSub/PubSubHubbub</code> from the dashboard sidebar:</p>\n<a href=\"https://aperture-proxy.p3k.io/23804a0f80c29a8632accb3584b1316b711bd2fa/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f7765627375622e706e67\"><img src=\"https://aperture-proxy.p3k.io/23804a0f80c29a8632accb3584b1316b711bd2fa/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f7765627375622e706e67\" alt=\"\" /></a>\n<p>We point it at <code>https://bridgy-fed.superfeedr.com</code>.</p>\n<h4>Atom feed</h4>\n<p>Like the WebSub stuff, I\u2019m not 100% sure why we need this, but I figure it\u2019s for similar reasons as to WebSub. I think it\u2019s what Fediverse clients expect you to have a feed in if they\u2019re looking for a list of your posts.</p>\n<p>WordPress is a bit annoying here in that while it does have an Atom feed of your posts built in, by default it doesn\u2019t advertise it in your HTML source. We need to add it in ourselves.</p>\n<p>There used to be a plugin for this, but it recently got deprecated. As per Bridge Fed\u2019s instructions, we can add it in manually by adding to the <code><head></code> section:</p>\n\n<pre><code><link rel=\"alternate\" type=\"application/atom+xml\" href=\"https://[YOURDOMAIN]/?feed=atom\" /></code></pre>\n\n<p>in the relevant part of your theme. (In SemPress, you\u2019d add it in to <code>header.php</code>).</p>\n<h4>Oi, webfingers</h4>\n<p>Webfinger is a protocol for discovery of info about users on the web. It uses an email like syntax, e.g. neil@doubleloop.net. Parts of the Fediverse use it to search for people and get info about them. I don\u2019t know all the details of how it works yet (you can read about <a href=\"https://github.com/tootsuite/mastodon/issues/1441\">what Mastodon expects</a>), but luckily I don\u2019t really need to know just yet, as Bridgy Fed takes care of it for me. All I need to do is forward on any Webfinger requests to Bridgy Fed.</p>\n<p>(Side note: Indieweb generally doesn\u2019t use webfinger \u2013 preferring to use a website\u2019s URL and its h-card as the means of discovering user information. <a href=\"https://indieweb.org/WebFinger\">Read more why</a>).</p>\n<p>As per the Bridgy Fed instructions, we can do this with the <a href=\"https://wordpress.org/plugins/safe-redirect-manager/\">Safe Redirect Manager</a> plugin. We just add the following two redirect rules:</p>\n<pre><code>/.well-known/host-meta* => https://fed.brid.gy/.well-known/host-meta*\n/.well-known/webfinger* => https://fed.brid.gy/.well-known/webfinger* </code></pre>\n<p>So whenever someone on the Fediverse tries to search for me via webfinger, e.g. @me@solarsailer.doubleloop.net, they\u2019ll end up making a request to <a href=\"https://solarsailer.doubleloop.net/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net\">solarsailer.doubleloop.net/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net</a>, and that gets forwarded on to Bridgy Fed at <a href=\"https://fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net\">fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net</a>.</p>\n<p>(Interestingly, whatever account you search for, the prefix part of it always comes back as the full domain name \u2013 e.g. @me@solarsailer.doubleloop.net, @yo@solarsailer.doubleloop.net, @foo@solarsailer.doubleloop.net, all come back as @solarsailer.doubleloop.net@solarsailer.doubleloop.net. Don\u2019t know why, but that is actually the expected behaviour, it\u2019s in the Bridgy Fed docs.)</p>\n<p>(Other side note: I\u2019m using <a href=\"http://solarsailer.doubleloop.net/\">solarsailer.doubleloop.net</a> here, rather than <a href=\"http://doubleloop.net/\">doubleloop.net</a>, as I\u2019m testing it all out on a separate install to my main site.)</p>\n<p>Bridgy Fed then returns the profile info needed. Some of which it pulls from links in my own page source (e.g. the location of my Atom feed), and from my h-card.</p>\n<h4>Reprezentin\u2019</h4>\n<p>Part of the reason I know it checks the h-card is I was getting an error at first, like so:</p>\n<blockquote><p>Couldn\u2019t find a <a href=\"http://microformats.org/wiki/representative-hcard-parsing\">representative h-card</a> on <a href=\"https://solarsailer.doubleloop.net/\">solarsailer.doubleloop.net/</a></p></blockquote>\n<p>Hmm, OK. You can test your h-card setup with the very handy <a href=\"https://indiewebify.me/\">indiewebify.me</a>.</p>\n<p>(e.g. <a href=\"https://indiewebify.me/validate-h-card/?url=https%3A%2F%2Fsolarsailer.doubleloop.net%2F\">indiewebify.me/validate-h-card/?url=https%3A%2F%2Fsolarsailer.doubleloop.net%2F</a>)</p>\n<p>The result was looking OK there. My h-card <em>seemed</em> to be representing me, but not to Bridgy Fed!</p>\n<p>Not sure why that is. It has classes of \u201cu-uid\u201d and \u201cu-url\u201d in the h-card link to my site. I found that if I also add in rel=\u201dme\u201d, then it\u2019s alright. The quick and dirty way of doing that was to stop using the h-card WordPress widget, copy and paste its mark up in to a Custom HTML widget, and add for the website link, where it has rel=\u201dauthor\u201d, add in \u201cme\u201d (so you end up with rel=\u201dauthor me\u201d).</p>\n<p>Try again after that change, it worked fine: <a href=\"https://fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net\">fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net</a> returns a bunch of json-formatted profile info.</p>\n<h2>Following from the Fedi</h2>\n<p>You should now be able to search for and follow your Fediconversant WordPress site from a Mastodon instance:</p>\n<a href=\"https://aperture-proxy.p3k.io/94a99000790b73c4ed2edf9c5889591a550b1a7c/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d666f6c6c6f772e706e67\"><img src=\"https://aperture-proxy.p3k.io/94a99000790b73c4ed2edf9c5889591a550b1a7c/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d666f6c6c6f772e706e67\" alt=\"\" /></a>\n<p>Nice!</p>\n<p>(As mentioned in the webfinger section, notice that the full account name is @solarsailer.doubleloop.net@solarsailer.doubleloop.net, even though I search for @me@solarsailer.doubleloop.net.)</p>\n<p>And on my /mentions page:</p>\n<a href=\"https://aperture-proxy.p3k.io/9e3b502d7dd2de00ddc5ae8395964875fd3046c0/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d666f6c6c6f772d646973706c61792e706e67\"><img src=\"https://aperture-proxy.p3k.io/9e3b502d7dd2de00ddc5ae8395964875fd3046c0/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d666f6c6c6f772d646973706c61792e706e67\" alt=\"\" /></a>\n<p>(Needs some formatting improvements, but hey there it is.)</p>\n<h2>Posting to the Fediverse, interacting back</h2>\n<p>So now if I create a post on my WordPress site, if should appear to my followers in the Fediverse. If someone likes it on the Fediverse, I should get a comment on my post. How cool is that!</p>\n<p>When creating the post, I need to make sure that it is sent to Bridgy Fed:</p>\n<a href=\"https://aperture-proxy.p3k.io/6a3c86dffae8120d7dbd777795c79f7e79ca4b53/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d706f7374696e672d612d6e6f74652e706e67\"><img src=\"https://aperture-proxy.p3k.io/6a3c86dffae8120d7dbd777795c79f7e79ca4b53/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d706f7374696e672d612d6e6f74652e706e67\" alt=\"\" /></a>\n<p>Lo and behold:</p>\n<a href=\"https://aperture-proxy.p3k.io/6af39ef2b27cbe458267899514b0c2a314c98f09/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e646976657273652d6d6173746f646f6e2d6e6f74652d616e642d6c696b652e706e67\"><img src=\"https://aperture-proxy.p3k.io/6af39ef2b27cbe458267899514b0c2a314c98f09/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e646976657273652d6d6173746f646f6e2d6e6f74652d616e642d6c696b652e706e67\" alt=\"\" /></a>\n<p>(Don\u2019t know why it\u2019s got the note set as a content warning \u2013 something to look at\u2026)</p>\n<p>And the like came back:</p>\n<a href=\"https://aperture-proxy.p3k.io/a7679f38fa41ee793c15bc2842e66cecd9a02da5/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d6e6f74652d616e642d6c696b652e706e67\"><img src=\"https://aperture-proxy.p3k.io/a7679f38fa41ee793c15bc2842e66cecd9a02da5/68747470733a2f2f646f75626c656c6f6f702e6e65742f77702d636f6e74656e742f75706c6f6164732f323031392f30352f696e64696576657273652d6e6f74652d616e642d6c696b652e706e67\" alt=\"\" /></a>\n<p><img src=\"https://aperture-proxy.p3k.io/2cd6afc700925392e4026bf84e6d06bc786f5e99/68747470733a2f2f732e772e6f72672f696d616765732f636f72652f656d6f6a692f31312f37327837322f31663362352e706e67\" alt=\"\ud83c\udfb5\" /> ..I made a note and I liked it.. <img src=\"https://aperture-proxy.p3k.io/2cd6afc700925392e4026bf84e6d06bc786f5e99/68747470733a2f2f732e772e6f72672f696d616765732f636f72652f656d6f6a692f31312f37327837322f31663362352e706e67\" alt=\"\ud83c\udfb5\" /></p>\n<h2>Quirks</h2>\n<p>So it\u2019s pretty awesome when you think about it. Your Indieweb site can be discovered and followed by people on the Fediverse through the usual means; your posts get automatically sent to any followers; and you get their interactions back. Indieverse! Fediweb!</p>\n<p>A few quirks I\u2019ve noticed that need ironing out before it\u2019s prime time and ready to be put on my main site:</p>\n<ul><li>as mentioned, when you send a note, the note content appears both as a content warning with \u2018Show More\u2019, as well as the content of the note</li>\n<li>relatedly, replies don\u2019t seem to work \u2013 you seem to get the content warning name back, rather than the actual content of the reply</li>\n<li>you have to decide per post if you want it to send to Fediverse \u2013 you could argue that this is a feature, but it might be nice to have an option to have it turned on by default</li>\n<li>the display name of Fediversians who\u2019ve interacted with you come back as fed.brid.gy (the solution to this being here though I think: <a href=\"https://brid.gy/about#appspot\">brid.gy/about#appspot</a>)</li>\n<li>when someone replies to you on the Fediverse, you get an interaction on your specific post <em>and</em> a generic webmention</li>\n</ul><h2>Wrap up</h2>\n<p>Well.. that was a long one!</p>\n<p>I think I\u2019ll take a deep dive into the technical nitty gritty of how Bridgy Fed works next. It\u2019s really interesting to learn how these protocols overlap, how they translate to each other, and where they disagree. I feel like I\u2019m learning more about the general patterns of decentralised social media by playing with two implementations of it at once.</p>\n<p>The post <a href=\"https://doubleloop.net/2019/05/04/bridging-the-indieweb-and-the-fediverse-part-2/\">Bridging the Indieweb and the Fediverse, part 2</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "In part 1, I discussed why you might want to bridge your Indieweb site to the Fediverse.\nIn this follow up post, I\u2019ll describe one way of doing it that I\u2019ve been tinkering with recently.\nThe tl;dr: using WordPress Indieweb plugins and Bridgy Fed; it works pretty smoothly; still a few quirks at present; it\u2019s awesome and lots of fun to mess around with.\n\n\n\nQuick preamble (as if the last post wasn\u2019t enough!). Indieweb is chiefly about having your own site. It certainly doesn\u2019t have to be WordPress \u2013 there are a plurality of projects out there, pretty much in every language/framework under the sun. And in fact, just having a single page at your own URL is being part of the Indieweb. All this stuff is just extra sugar on top.\nAdditionally, you don\u2019t need Bridgy Fed to wire a WordPress site up to the Fediverse \u2013 you could bypass all the Indieweb plugins and use pterotype, or WordPress ActivityPub.\nBut that said, I have a WordPress Indieweb site, and I want to use Bridgy Fed, so here I\u2019ll talk about that combination. Ready to shave some yaks? Let\u2019s go!\nInstalling WordPress\nIt\u2019s outside the scope of this article to go through WordPress installation steps, but it\u2019s pretty simple and there\u2019s a million and one resources out there already on how to do so. For the purposes of this blog post, you just need to get to the point of having a fresh WP install.\nThere\u2019s various different ways to install your own WordPress:\nyou can pay WordPress.com \u2013 I\u2019ve never tried it for an Indieweb site, and I think you need something like \u2018Business Class\u2019 to install any non-Automattic sanctioned plugins such as the Indieweb ones\nyou can use a web hosting service \u2013 99.999% of shared hosting providers will have a one click install of WordPress. For example, Gandi.\nyou can install it on your own server \u2013 I\u2019ve done it here for my testing with a Digital Ocean dedicated WordPress droplet, where you get a virtual private server (VPS) with all the LAMP bits and pieces that you need preconfigured, and WordPress ready to rock. But my main site is a manual WP install on a barebones VPS at cloudvault.me.\nI personally like installing on a VPS as I like to tinker around with other bits and pieces on the server, but it is by no means necessary. Everything in this post should work wherever you have WordPress installed. If you\u2019re new to it, I\u2019d probably recommend using a 1click install on a shared hosting service.\nSetting up the Indieweb plugins\nAlright, so let\u2019s assume we have a fresh install of WordPress, all ready to rock.\nNext up for us is to get it indiewebified.\nIndiewebify.me\nThere\u2019s a fantastic bunch of WordPress plugins that will add all of the Indieweb functionality to our site. For the purposes of our Fediverse bridgying, we don\u2019t need all of them, but we\u2019ll use a fair few. The individual pieces we\u2019ll be needing are: Webmentions; Post Kinds; Syndication Links; Semantic Linkbacks; and WebSub. And we\u2019ll need a theme that supports microformats, for which we\u2019ll go with SemPress.\nBut before all that, first off, we\u2019ll install the main Indieweb plugin. This gives us a central place in the WordPress dashboard to manage our other Indieweb plugins, and adds a couple of the Indieweb building blocks itself.\nGo to Plugins -> Add New and search for Indieweb. Then, install and activate the plugin.\n\nOnce activated, you\u2019ll get a new Indieweb section in your dashboard sidebar:\n\nGo to Getting Started and have a read through \u2013 it gives some nice general information on getting started with Indieweb in WordPress. We will have a good read of that, won\u2019t we, and then we\u2019ll start to activate the relevant subplugins for our purposes today.\nPlug me in\nIn the dashboard sidebar, go to Indieweb / Extensions. This gives us a nice little one stop shop to install Indieweb related plugins.\n\nWe\u2019ll just install and activate the Indieweb plugins that we need for our fedibridge right now. For each one described below, hit \u2018Install Now\u2019 and then \u2018Activate\u2019.\nPost Kinds\nPost Kinds helps us to publish different socialmedia-y microbloggy types of posts on our WordPress site. So this is things like notes, photos, likes, replies, reposts, RSVPs to events, that kind of thing. We could do it all without Post Kinds if we wanted, but Post Kinds helps us think about the various bits of meta-info we might need on different types of posts. And it gives us a little assist in some of the markup that is needed once we start sending notification of these posts to other people and places.\nWebmention\nOK, say we\u2019ve posted something to our site. If it\u2019s supposed to be interacting with someone else, how does that get to them?\nAs mentioned in the last post, Webmentions are the server-to-server (or you could just think site-to-site) bits of Indieweb communication. When you do something on your site that is an interaction with someone else (e.g. mentioning them, liking one of their posts, etc), you\u2019ll send them a webmention. It crosses the intertubes and delivers a fresh little bit of indielove straight into their website.\nThe Webmention plugin also deals with your site receiving webmentions from other people. People like something of yours from their site \u2013 you get notified.\nQuick bit of config for webmentions: some of the webmentions you receive might be an action tied to a specific post of yours \u2013 someone liked it, or someone replied to it. But othertimes it might be that someone wrote a note and just mentioned you in it, it\u2019s not in response to something in particular. For this we can set up a generic mentions page which is a bucket for all those non-post-specific mentions to go into.\nSo create a WordPress page called, for example, \u2018Mentions\u2019. Then, go to Indieweb -> Webmentions and change the section Webmention support for pages. Yes, we want them, and we also want to choose our newly created page for generic webmentions to go to.\n\nSemantic Linkbacks\nSpeaking of receiving webmentions\u2026 they come back to us as WordPress comments. The Semantic Linkbacks plugin gives us an assist in formatting those comments a bit better.\nSyndication Links\nOK so so far we\u2019re posting posts, and then sending notifications to any Indieweb sites that we interact with. We\u2019re even receiving things back from other sites. But what if we want to also send these posts to an account on a platform somewhere else \u2013 for example, Twitter? Well that\u2019s called syndication, and part of the general principle of POSSEing \u2013 publish on your own site, syndicate elsewhere. Syndication Links helps us with that.\nThe same plugin also helps us send stuff to Bridgy Fed, to forward on to the Fediverse \u2013 but note that despite this plugin helping us out here, using Bridgy Fed isn\u2019t really syndication, as we don\u2019t have a Fediverse account somewhere else that we\u2019re sending to \u2013 our WordPress site is the account/actor on the Fediverse.\nWebSub\nI\u2019ll be completely honest, I\u2019m not 100% where the WebSub plugin fits into our setup here, but as stated by Bridgy Fed:\nIf you want people on fedsocnets to see your posts, your site will also need to support WebSub (n\u00e9e PubSubHubbub). Specifically, your Atom feed needs to advertise it.\nWebSub in general provides a way for online content to be distributed via hubs, with subscribers subscribing to notifications of updates from publishers publishing to the hub. I kind of thought Bridgy Fed was already being a hub of sorts for us, where we publish via webmention and it notifies Fediverse subscribers via ActivityPub. So I\u2019m not sure what the extra hub setup does. It might be that Bridgy Fed is dealing with direct interactions, and WebSub is dealing with subscriptions to our feed of content. Not sure \u2013 I plan at some point to take a deeper read into how everything works (and hopefully to write about it too) \u2013 but for now let\u2019s just focus on setting it up!\nMicroformats\nOne final thing \u2013 microformats. Microformats are a way of marking up your HTML with a little bit of extra data that makes it more amenable to machine reading. This is useful for another application to e.g. figure out who\u2019s the author of a post, or the owner of a site, or for knowing what a \u2018like\u2019 post is actually liking. It\u2019s an inline format, as opposed to something like RSS or Atom feeds, which are contained in separate files. Bridgy Fed will look at your microformats when you send it a webmention about something on your site \u2013 it\u2019ll come and inspect that post to figure out some of the meta data.\nTwo ways to get microformats on your site are:\ninstall and use the SemPress theme, which has microformats support out of the box\ninstall the Microformats 2 plugin from the Indieweb Extensions gallery, which will try its best to mark up an existing theme with microformats\nI\u2019ve only ever used SemPress or customisations of it, so can\u2019t speak to the efficacy of the Microformats 2 plugin.\nh-cards: Hi, my name is\nOne special microformat in particular is the h-card format. This is a way of stating who the owner of the site is (and who the author of a post is).\nThe Indieweb plugin provides a WordPress widget for h-cards that you can add in to a sidebar. You\u2019ll find it in Appearance -> Widgets, and it\u2019s called Author Profile H-Card. It will take your details out of your user profile in WordPress, and will both display these details wherever you put your widget, and mark them up in h-card format for machine parsing.\n\nAlrighty then! That\u2019s it, plugin wise. Well \u2013 for now. Let\u2019s not forget about the remaining plugins. Micropub and IndieAuth are key parts of a fulsome Indieweb setup, allowing for the client-to-server communication I mentioned previously. It\u2019s super cool stuff, allowing you to post to your site from multiple 3rd party clients. Definitely worth setting up \u2013 but we don\u2019t need it for the purposes of this article, as we can just create posts in the WordPress interface for now.\n(Last but not least: the Simple Location plugin helps you out with doing check-in posts.)\nBridgy Fed configuration\nLet\u2019s take it to the bridgy! Everything up until this point is all stuff that is generally applicable to a WordPress Indieweb site. (Hence why it\u2019s all been in the Indieweb dashboard section so far). There\u2019s a few extra bits of config we need to do specifically for Bridgy Fed that haven\u2019t made it into the Indieweb dashboard just yet.\nWebSub hub\nOne extra thing we need to do with the WebSub plugin is change the WebSub hub that we\u2019re pointing. We can do that in Options -> WebSub/PubSubHubbub from the dashboard sidebar:\n\nWe point it at https://bridgy-fed.superfeedr.com.\nAtom feed\nLike the WebSub stuff, I\u2019m not 100% sure why we need this, but I figure it\u2019s for similar reasons as to WebSub. I think it\u2019s what Fediverse clients expect you to have a feed in if they\u2019re looking for a list of your posts.\nWordPress is a bit annoying here in that while it does have an Atom feed of your posts built in, by default it doesn\u2019t advertise it in your HTML source. We need to add it in ourselves.\nThere used to be a plugin for this, but it recently got deprecated. As per Bridge Fed\u2019s instructions, we can add it in manually by adding to the <head> section:\n\n<link rel=\"alternate\" type=\"application/atom+xml\" href=\"https://[YOURDOMAIN]/?feed=atom\" />\n\nin the relevant part of your theme. (In SemPress, you\u2019d add it in to header.php).\nOi, webfingers\nWebfinger is a protocol for discovery of info about users on the web. It uses an email like syntax, e.g. neil@doubleloop.net. Parts of the Fediverse use it to search for people and get info about them. I don\u2019t know all the details of how it works yet (you can read about what Mastodon expects), but luckily I don\u2019t really need to know just yet, as Bridgy Fed takes care of it for me. All I need to do is forward on any Webfinger requests to Bridgy Fed.\n(Side note: Indieweb generally doesn\u2019t use webfinger \u2013 preferring to use a website\u2019s URL and its h-card as the means of discovering user information. Read more why).\nAs per the Bridgy Fed instructions, we can do this with the Safe Redirect Manager plugin. We just add the following two redirect rules:\n/.well-known/host-meta* => https://fed.brid.gy/.well-known/host-meta*\n/.well-known/webfinger* => https://fed.brid.gy/.well-known/webfinger* \nSo whenever someone on the Fediverse tries to search for me via webfinger, e.g. @me@solarsailer.doubleloop.net, they\u2019ll end up making a request to solarsailer.doubleloop.net/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net, and that gets forwarded on to Bridgy Fed at fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net.\n(Interestingly, whatever account you search for, the prefix part of it always comes back as the full domain name \u2013 e.g. @me@solarsailer.doubleloop.net, @yo@solarsailer.doubleloop.net, @foo@solarsailer.doubleloop.net, all come back as @solarsailer.doubleloop.net@solarsailer.doubleloop.net. Don\u2019t know why, but that is actually the expected behaviour, it\u2019s in the Bridgy Fed docs.)\n(Other side note: I\u2019m using solarsailer.doubleloop.net here, rather than doubleloop.net, as I\u2019m testing it all out on a separate install to my main site.)\nBridgy Fed then returns the profile info needed. Some of which it pulls from links in my own page source (e.g. the location of my Atom feed), and from my h-card.\nReprezentin\u2019\nPart of the reason I know it checks the h-card is I was getting an error at first, like so:\nCouldn\u2019t find a representative h-card on solarsailer.doubleloop.net/\nHmm, OK. You can test your h-card setup with the very handy indiewebify.me.\n(e.g. indiewebify.me/validate-h-card/?url=https%3A%2F%2Fsolarsailer.doubleloop.net%2F)\nThe result was looking OK there. My h-card seemed to be representing me, but not to Bridgy Fed!\nNot sure why that is. It has classes of \u201cu-uid\u201d and \u201cu-url\u201d in the h-card link to my site. I found that if I also add in rel=\u201dme\u201d, then it\u2019s alright. The quick and dirty way of doing that was to stop using the h-card WordPress widget, copy and paste its mark up in to a Custom HTML widget, and add for the website link, where it has rel=\u201dauthor\u201d, add in \u201cme\u201d (so you end up with rel=\u201dauthor me\u201d).\nTry again after that change, it worked fine: fed.brid.gy/.well-known/webfinger?resource=acct:me@solarsailer.doubleloop.net returns a bunch of json-formatted profile info.\nFollowing from the Fedi\nYou should now be able to search for and follow your Fediconversant WordPress site from a Mastodon instance:\n\nNice!\n(As mentioned in the webfinger section, notice that the full account name is @solarsailer.doubleloop.net@solarsailer.doubleloop.net, even though I search for @me@solarsailer.doubleloop.net.)\nAnd on my /mentions page:\n\n(Needs some formatting improvements, but hey there it is.)\nPosting to the Fediverse, interacting back\nSo now if I create a post on my WordPress site, if should appear to my followers in the Fediverse. If someone likes it on the Fediverse, I should get a comment on my post. How cool is that!\nWhen creating the post, I need to make sure that it is sent to Bridgy Fed:\n\nLo and behold:\n\n(Don\u2019t know why it\u2019s got the note set as a content warning \u2013 something to look at\u2026)\nAnd the like came back:\n\n ..I made a note and I liked it.. \nQuirks\nSo it\u2019s pretty awesome when you think about it. Your Indieweb site can be discovered and followed by people on the Fediverse through the usual means; your posts get automatically sent to any followers; and you get their interactions back. Indieverse! Fediweb!\nA few quirks I\u2019ve noticed that need ironing out before it\u2019s prime time and ready to be put on my main site:\nas mentioned, when you send a note, the note content appears both as a content warning with \u2018Show More\u2019, as well as the content of the note\nrelatedly, replies don\u2019t seem to work \u2013 you seem to get the content warning name back, rather than the actual content of the reply\nyou have to decide per post if you want it to send to Fediverse \u2013 you could argue that this is a feature, but it might be nice to have an option to have it turned on by default\nthe display name of Fediversians who\u2019ve interacted with you come back as fed.brid.gy (the solution to this being here though I think: brid.gy/about#appspot)\nwhen someone replies to you on the Fediverse, you get an interaction on your specific post and a generic webmention\nWrap up\nWell.. that was a long one!\nI think I\u2019ll take a deep dive into the technical nitty gritty of how Bridgy Fed works next. It\u2019s really interesting to learn how these protocols overlap, how they translate to each other, and where they disagree. I feel like I\u2019m learning more about the general patterns of decentralised social media by playing with two implementations of it at once.\nThe post Bridging the Indieweb and the Fediverse, part 2 appeared first on doubleloop." }, "name": "Bridging the Indieweb and the Fediverse, part 2", "post-type": "note", "_id": "3307877", "_source": "1895", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/05/04/5325/", "published": "2019-05-04T09:50:22+00:00", "content": { "html": "<p>IndieWebCamp Berlin is ON!</p>\n<p>I\u2019m not there so am following along in the chat (<a href=\"https://chat.indieweb.org/2019-05-04\">chat.indieweb.org/2019-05-04</a>). Bits and pieces will also be being livestreamed (<a href=\"https://v.mozilla.com/flex.html?roomdirect.html&key=uRIeFq6SA8\">v.mozilla.com/flex.html?roomdirect.html&key=uRIeFq6SA8</a>) through the weekend.</p>\n<p>The post <a href=\"https://doubleloop.net/2019/05/04/5325/\">#5325</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "IndieWebCamp Berlin is ON!\nI\u2019m not there so am following along in the chat (chat.indieweb.org/2019-05-04). Bits and pieces will also be being livestreamed (v.mozilla.com/flex.html?roomdirect.html&key=uRIeFq6SA8) through the weekend.\nThe post #5325 appeared first on doubleloop." }, "name": "#5325", "post-type": "note", "_id": "3302082", "_source": "1895", "_is_read": true }
{ "type": "entry", "published": "2019-05-03T17:21:40+10:00", "url": "https://unicyclic.com/mal/2019-05-03-This_is_great_writing_from_Greg_Seven_Steps_to_P", "category": [ "indieweb" ], "content": { "text": "This is great writing from Greg: Seven Steps to #ProSocialWeb", "html": "This is great writing from Greg: <a href=\"https://quickthoughts.jgregorymcverry.com/2019/04/25/seven-steps-to-prosocialweb\">Seven Steps to #ProSocialWeb</a>" }, "author": { "type": "card", "name": "Malcolm Blaney", "url": "https://unicyclic.com/mal", "photo": "https://aperture-proxy.p3k.io/4f46272c0027449ced0d7cf8de31ea1bec37210e/68747470733a2f2f756e696379636c69632e636f6d2f6d616c2f7075626c69632f70726f66696c655f736d616c6c5f7468756d622e706e67" }, "post-type": "note", "_id": "3287509", "_source": "243", "_is_read": true }
{ "type": "event", "name": "IndieWebCamp D\u00fcsseldorf", "summary": "In town for beyond tellerrand D\u00fcsseldorf May 13-14 and not otherwise busy on May 11-12?\nMarc Thiele, Joschi Kuphal, and I are looking forward to welcoming you again. We're meeting for a two-day BarCamp collaboration in D\u00fcsseldorf. Brainstorming, working, teaching, helping each other and much more. Join us on Saturday the 11th & Sunday the 12th and get your ideas out of your head and your hands dirty.\nBoth days are free to attend!\nMore information: #btconf IndieWebCamp D\u00fcsseldorf description IndieWeb Wiki Event Page\nAny questions? Ask in #indieweb Slack or IRC\nRSVP: btco.nf/DUS2019indiewebcamp", "published": "2019-04-23 23:48-0700", "start": "2019-05-11 10:00-0700", "end": "2019-05-12 18:00-0700", "url": "http://tantek.com/2019/131/e1/indiewebcamp-dusseldorf", "location": [ "http://tantek.com/sipgate" ], "content": { "text": "When: 2019-05-11 10:00\u20262019-05-12 18:00\nWhere: sipgate\n\n\n\n\nIn town for beyond tellerrand D\u00fcsseldorf May 13-14 and not otherwise busy on May 11-12?\n\n\nMarc Thiele, Joschi Kuphal, and I are looking forward to welcoming you again. We're meeting for a two-day BarCamp collaboration in D\u00fcsseldorf. Brainstorming, working, teaching, helping each other and much more. Join us on Saturday the 11th & Sunday the 12th and get your ideas out of your head and your hands dirty.\n\nBoth days are free to attend!\n\nMore information: \n\n#btconf IndieWebCamp D\u00fcsseldorf description\nIndieWeb Wiki Event Page\n\nAny questions? Ask in \n#indieweb Slack or IRC\n\n\nRSVP: btco.nf/DUS2019indiewebcamp", "html": "<p>\nWhen: <time class=\"dt-start\">2019-05-11 10:00</time>\u2026<time class=\"dt-end\">2019-05-12 18:00</time><span>\nWhere: <span class=\"u-location h-card\">sipgate</span>\n</span>\n</p>\n\n<p>\nIn town for <a href=\"https://beyondtellerrand.com/events/duesseldorf-2019\">beyond tellerrand D\u00fcsseldorf</a> May 13-14 and not otherwise busy on May 11-12?\n</p>\n<p>\nMarc Thiele, Joschi Kuphal, and I are looking forward to welcoming you again. We're meeting for a two-day BarCamp collaboration in D\u00fcsseldorf. Brainstorming, working, teaching, helping each other and much more. Join us on Saturday the 11th & Sunday the 12th and get your ideas out of your head and your hands dirty.\n</p>\n<p>Both days are free to attend!</p>\n<p>\nMore information: \n</p>\n<ul><li><a class=\"u-url\" href=\"https://beyondtellerrand.com/events/duesseldorf-2019/side-events/indiewebcamp\">#btconf IndieWebCamp D\u00fcsseldorf description</a></li>\n<li><a class=\"u-url\" href=\"https://indieweb.org/2019/D%C3%BCsseldorf\">IndieWeb Wiki Event Page</a></li>\n</ul><p>\nAny questions? Ask in \n<a href=\"https://indieweb.org/discuss\">#indieweb Slack or IRC</a>\n</p>\n<p>\nRSVP: <a href=\"https://btco.nf/DUS2019indiewebcamp\">btco.nf/DUS2019indiewebcamp</a>\n</p>" }, "post-type": "event", "_id": "3286670", "_source": "1", "_is_read": true }
{ "type": "entry", "published": "2019-05-02 22:42-0700", "url": "http://tantek.com/2019/122/t1/last-call-indiewebcamp-tickets", "category": [ "Berlin", "IndieWebCamp", "InternetHealth", "OpenWeb", "IndieWeb" ], "content": { "text": "#Berlin friends, I am in your fine city!\n\nLast call for #IndieWebCamp tickets @MozillaBerlin!\nNo cost sign-up: https://2019.indieweb.org/berlin\n\nLet's chat & hack to improve #InternetHealth #OpenWeb #IndieWeb!\nCC: @crh @leyink @nuzz @rosanardila @sonniesedge @tessa", "html": "#<span class=\"p-category\">Berlin</span> friends, I am in your fine city!<br /><br />Last call for #<span class=\"p-category\">IndieWebCamp</span> tickets <a class=\"h-cassis-username\" href=\"https://twitter.com/MozillaBerlin\">@MozillaBerlin</a>!<br />No cost sign-up: <a href=\"https://2019.indieweb.org/berlin\">https://2019.indieweb.org/berlin</a><br /><br />Let's chat & hack to improve #<span class=\"p-category\">InternetHealth</span> #<span class=\"p-category\">OpenWeb</span> #<span class=\"p-category\">IndieWeb</span>!<br />CC: <a class=\"h-cassis-username\" href=\"https://twitter.com/crh\">@crh</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/leyink\">@leyink</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/nuzz\">@nuzz</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/rosanardila\">@rosanardila</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/sonniesedge\">@sonniesedge</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/tessa\">@tessa</a>" }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "note", "_id": "3286671", "_source": "1", "_is_read": true }
{ "type": "entry", "published": "2019-05-02T20:52:37+00:00", "url": "https://cleverdevil.io/2019/why-im-supporting-the-indieweb-and-you-should-too", "syndication": [ "https://twitter.com/cleverdevil/status/1124054139758153728", "https://mastodon.social/@cleverdevil/102028435039820592" ], "bookmark-of": [ "https://www.marketgoo.com/blog/2019/04/30/why-support-indieweb/" ], "name": "Why I'm supporting the IndieWeb (and you should too) - MarketGoo", "content": { "text": "Great post from\u00a0Wences Garc\u00eda\u00a0of MarketGoo\u00a0on the IndieWeb. I met Wences and the MarketGoo team a few years ago, and was so impressed with their culture, energy, and values. Its fantastic to see them sharing those values with the world in such a positive way.\nIt\u2019s still too early to reach any conclusions, but I\u2019m feeling better now that I control my own content and that I\u2019ve found a place where to post my content freely and without fear.\nBut will be the Indieweb movement be the solution to save us all? The struggles I had at the beginning setting up my IndieWeb on a WordPress website have prevented me from thinking that way.\nIt\u2019s clear that the IndieWeb needs to be more convenient, otherwise non-early adopters will not even get close to this movement.\nI think Wences is right that with many building blocks now in place, it is important to start making the IndieWeb more user-friendly. Its no coincidence that Wences' web presence is now on Micro.blog, which is a much more approachable platform.", "html": "<p>Great post from\u00a0<a href=\"http://www.wences.com\">Wences Garc\u00eda</a>\u00a0of <a href=\"https://www.marketgoo.com\">MarketGoo</a>\u00a0on the <a href=\"https://indieweb.org\">IndieWeb</a>. I met Wences and the MarketGoo team a few years ago, and was so impressed with their culture, energy, and values. Its fantastic to see them sharing those values with the world in such a positive way.</p><blockquote>\n<p>It\u2019s still too early to reach any conclusions, but I\u2019m feeling better now that I control my own content and that I\u2019ve found a place where to post my content freely and without fear.</p>\n<p>But will be the Indieweb movement be the solution to save us all? The struggles I had at the beginning setting up my IndieWeb on a WordPress website have prevented me from thinking that way.</p>\n<p>It\u2019s clear that the IndieWeb needs to be more convenient, otherwise non-early adopters will not even get close to this movement.</p>\n</blockquote><p>I think Wences is right that with many building blocks now in place, it is important to start making the IndieWeb more user-friendly. Its no coincidence that Wences' web presence is now on <a href=\"http://micro.blog\">Micro.blog</a>, which is a much more approachable platform.</p>" }, "author": { "type": "card", "name": "Jonathan LaCour", "url": "https://cleverdevil.io/profile/cleverdevil", "photo": "https://aperture-proxy.p3k.io/77e5d6e5871324c43aebf2e3e7a5553e14578f66/68747470733a2f2f636c65766572646576696c2e696f2f66696c652f66646263373639366135663733383634656131316138323863383631653133382f7468756d622e6a7067" }, "post-type": "bookmark", "_id": "3280252", "_source": "71", "_is_read": true }
I’ll be homebrewing my website in @68MiddleSt from 6pm to 7:30pm this evening. You can join the club.
{ "type": "entry", "published": "2019-05-02T15:43:43Z", "url": "https://adactio.com/notes/15112", "syndication": [ "https://twitter.com/adactio/status/1123976370743324673" ], "content": { "text": "I\u2019ll be homebrewing my website in @68MiddleSt from 6pm to 7:30pm this evening. You can join the club.\n\nhttps://indieweb.org/HomebrewWebsiteClub#Brighton", "html": "<p>I\u2019ll be homebrewing my website in <a href=\"https://twitter.com/68MiddleSt\">@68MiddleSt</a> from 6pm to 7:30pm this evening. You can join the club.</p>\n\n<p><a href=\"https://indieweb.org/Homebrew_Website_Club#Brighton\">https://indieweb.org/Homebrew<em>Website</em>Club#Brighton</a></p>" }, "author": { "type": "card", "name": "Jeremy Keith", "url": "https://adactio.com/", "photo": "https://aperture-proxy.p3k.io/bbbacdf0a064621004f2ce9026a1202a5f3433e0/68747470733a2f2f6164616374696f2e636f6d2f696d616765732f70686f746f2d3135302e6a7067" }, "post-type": "note", "_id": "3275426", "_source": "2", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/05/01/bridging-the-indieweb-and-the-fediverse-with-bridgy-fed-part-1/", "published": "2019-05-01T23:05:07+00:00", "content": { "html": "<p>I experimented recently with setting up an Indieweb WordPress site as a standalone actor on the Fediverse. Thanks to the WordPress indieweb plugins, and Bridgy Fed, it\u2019s pretty easy to do, with a few quirks.</p>\n<p>This post is a bit of preamble as to what this means and why you might want to do it. Part 2 will go in to the details of one way to do it that I\u2019ve played with \u2013 via Bridgy Fed.</p>\n\n<h2>What\u2019s the Indieweb?</h2>\n<p>The <a href=\"https://indieweb.org/\">Indieweb</a> is a people-focused alternative to the \u201ccorporate web\u201d. You do most of the stuff you\u2019d do on Facebook, Twitter, Instagram, etc, including interacting with other people, but on a site that you control, with full ownership of all the things you post. It\u2019s a bit like a blog on steroids. You can build your own indieweb site from scratch, you can get a jumpstart with something like WordPress, or you can sign up with a site like <a href=\"https://micro.blog/\">micro.blog</a> where it\u2019s as simple as joining and using Twitter. There\u2019s tons more about the <a href=\"https://indieweb.org/why\">whys</a> and <a href=\"https://indieweb.org/Getting_Started\">hows</a> on the indieweb wiki.</p>\n<h2>What\u2019s the Fediverse?</h2>\n<p>As with the indieweb, the <a href=\"https://fediverse.party/en/fediverse/\">Fediverse</a> is a way to interact online, without belonging to the big social network silos. It\u2019s taken off in a big way of late thanks to Mastodon, but the ecosystem is much bigger than that.</p>\n<h2>What\u2019s the difference between them?</h2>\n<p>I\u2019m by no means an expert on either, but in my mind, at a very abstract level, in terms of goals, there\u2019s really not a whole lot of difference between the two. (<a href=\"https://dustycloud.org/blog/on-standards-divisions-collaboration/\">And they were in fact almost one</a>, if you read a bit of the history of their development!) At their heart they\u2019re both independent, decentralized ways to do social media outside of the big megacorps.</p>\n<p>That said, when you get in to the weeds of it there\u2019s definitely differences in approach, mostly in terms of the underlying protocols, the modes of implementation and hosting, and the flavours of decentralisation. There\u2019s also the community-aspect of both.</p>\n<h3>Protocols</h3>\n<p>In terms of protocols, you could write a whole series of posts on them. In a gross simplication, the main things are the client-to-server part \u2013 how users actually create posts; and the server-to-server part \u2013 how these posts get distributed out to other people. Fediverse is lately settling on primarily ActivityPub for this, and Indieweb has a collection of various protocols.</p>\n<h3>Hosting/decentralisation</h3>\n<p>From what I\u2019ve seen, Indieweb hosting <em>tends</em> to be more distributed/P2P, in that individuals set up their own sites that communicate with each other directly. The Fediverse <em>tends</em> to be federated, in that users join an existing <em>instance</em>, hosted by someone else, with hundreds of other users on those instances who also just have an account. (A simple way to think about federation is how email works \u2013 we don\u2019t all have to send messages through Mega Email Corp. You can be on Gmail, I can be on ProtonMail, someone else can be on AOL \u2013 yet we can all communicate back and forth because these services are using the same protocol. (Just.))</p>\n<p>But that said, you could think of joining something like micro.blog as kind of like joining an \u2018Indieweb instance\u2019, and you can quite easily host your own Fediverse instance with just you on it as the sole user, so the lines are blurred.</p>\n<h3>Implemention</h3>\n<p>There\u2019s more of a plurality of implementations on the Indieweb, in that a significant number of people have implemented the protocols on their site from scratch (with lots of reuse of tooling and libraries, of course). But there\u2019s also WordPress and Known implementations where you get much of the functionality out of the box. In the Fediverse, there\u2019s some flagship projects that implement ActivityPub and compatible protocols, such as Mastodon, Pleroma, Hubzilla, Pixelfed (and plenty others). But you could also build your own site and implement ActivityPub if you wanted, too.</p>\n<p>To my mind, any decentralisation effort should allow you to host your own installation if you want, and build your own implementation if you want, for those that love to tinker or want maximum control; OR get an account somewhere else, with absolutely minimal effort, for those that just want to get up and running. Both types should be able to communicate with each other, not caring about where they\u2019re hosted.</p>\n<p>Both the Indieweb and the Fediverse allow for both of those.</p>\n<h3>Community</h3>\n<p>The community-aspect could have blog posts a\u2019plenty by itself too. My own hot take on it is that the greater ease of getting an account means the Fediverse is bigger and more diverse. It\u2019s a frothing hotbed of lunatic fringes (and awesome because of that). Also with that seems to come a great deal of self-reflection of general community management (content warnings, etc).</p>\n<p>At present, the more P2P aspect of Indieweb makes it feel like it only has <em>one</em> community, itself. And that community (again, only my own observations as far as my interactions have taken me) feels very tech-oriented at present. All the great stuff happening with readers and groups might change that.</p>\n<h2>Why not just be on the Fediverse? Why not just be on the indieweb? Why be on both?</h2>\n<p>Personally speaking, I got involved with Indieweb before I found the Fediverse, and I like a number of aspects of it. I\u2019m also already part of the Fediverse, as I have an account on social.coop, and I like the people and discussions and interactions on there too. There\u2019s fun people on both, so why not be a part of both? Bridges not walls eh. I\u2019m of the opinion that different approaches help inform and improve each other; a positive symbiosis rather than a competition.</p>\n<h2>How to be on both</h2>\n<p>Focusing on WordPress, there\u2019s a few different ways that I\u2019ve come across to connect the Indieweb and the Fediverse:</p>\n<ul><li><a href=\"https://indieweb.org/POSSE\">POSSE</a>ing</li>\n<li><a href=\"https://getpterotype.com/\">pterotype</a></li>\n<li><a href=\"https://github.com/pfefferle/wordpress-activitypub\">wordpress actvitypub</a></li>\n<li><a href=\"https://fed.brid.gy/\">bridgy fed</a></li>\n</ul><h3>POSSE</h3>\n<p>The super simple way, which I currently do with my site, is the Indieweb concept of POSSEing \u2013 publish to your own site, syndicate elsewhere. When I make a post on my website, I send an additional copy to my social.coop account (and that\u2019s where I tend to get the most interaction at present.) I do this via the Mastodon Autopost plugin for indieweb and the Syndication Links plugin. One benefit of this approach for me is that I like the \u2018local\u2019 timeline of the social.coop instance, which is why I\u2019ve continued with an account there for so long. As an independent entity, I\u2019d lose some of that (unless perhaps I used a Fediverse platform that supporsed groups\u2026)</p>\n<h3>Pterotype and WordPress ActivityPub</h3>\n<p>Pterotype and WordPress ActivityPub are WordPress plugins that gives your blog an ActivityPub feed. Installing one of these plugins turns your site in to something that the rest of the Fediverse can see and follow as if you were on an instance. Other than the fact that you have a site that you own and control, these approaches are Indieweb agnostic. (Disclaimer: I haven\u2019t tried either.)</p>\n<h3>Bridgy Fed</h3>\n<p>And finally there\u2019s Bridgy Fed. Bridgy is an amazing long-runnning Indieweb service that creates various bridges between Indieweb sites and other social networks. It lets you get all the benefits of the Indieweb while still having a foot in the door of the old world of Twitter, Facebook, etc. It basically translates between the Indieweb method of server-to-server communication (Webmentions), and whatever language the other networks speak. Part of this translation is also pulling back interactions from the remote networks to your own site. And Bridgy Fed does this same thing, but for the Fediverse.</p>\n<p>To me, Bridgy Fed makes the most sense if you want to follow an Indieweb approach, but also want to exist on the Fediverse as an independent entity, and aren\u2019t tied to a particular instance already.</p>\n<p>The post <a href=\"https://doubleloop.net/2019/05/01/bridging-the-indieweb-and-the-fediverse-with-bridgy-fed-part-1/\">Bridging the Indieweb and the Fediverse with Bridgy Fed, part 1</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "I experimented recently with setting up an Indieweb WordPress site as a standalone actor on the Fediverse. Thanks to the WordPress indieweb plugins, and Bridgy Fed, it\u2019s pretty easy to do, with a few quirks.\nThis post is a bit of preamble as to what this means and why you might want to do it. Part 2 will go in to the details of one way to do it that I\u2019ve played with \u2013 via Bridgy Fed.\n\nWhat\u2019s the Indieweb?\nThe Indieweb is a people-focused alternative to the \u201ccorporate web\u201d. You do most of the stuff you\u2019d do on Facebook, Twitter, Instagram, etc, including interacting with other people, but on a site that you control, with full ownership of all the things you post. It\u2019s a bit like a blog on steroids. You can build your own indieweb site from scratch, you can get a jumpstart with something like WordPress, or you can sign up with a site like micro.blog where it\u2019s as simple as joining and using Twitter. There\u2019s tons more about the whys and hows on the indieweb wiki.\nWhat\u2019s the Fediverse?\nAs with the indieweb, the Fediverse is a way to interact online, without belonging to the big social network silos. It\u2019s taken off in a big way of late thanks to Mastodon, but the ecosystem is much bigger than that.\nWhat\u2019s the difference between them?\nI\u2019m by no means an expert on either, but in my mind, at a very abstract level, in terms of goals, there\u2019s really not a whole lot of difference between the two. (And they were in fact almost one, if you read a bit of the history of their development!) At their heart they\u2019re both independent, decentralized ways to do social media outside of the big megacorps.\nThat said, when you get in to the weeds of it there\u2019s definitely differences in approach, mostly in terms of the underlying protocols, the modes of implementation and hosting, and the flavours of decentralisation. There\u2019s also the community-aspect of both.\nProtocols\nIn terms of protocols, you could write a whole series of posts on them. In a gross simplication, the main things are the client-to-server part \u2013 how users actually create posts; and the server-to-server part \u2013 how these posts get distributed out to other people. Fediverse is lately settling on primarily ActivityPub for this, and Indieweb has a collection of various protocols.\nHosting/decentralisation\nFrom what I\u2019ve seen, Indieweb hosting tends to be more distributed/P2P, in that individuals set up their own sites that communicate with each other directly. The Fediverse tends to be federated, in that users join an existing instance, hosted by someone else, with hundreds of other users on those instances who also just have an account. (A simple way to think about federation is how email works \u2013 we don\u2019t all have to send messages through Mega Email Corp. You can be on Gmail, I can be on ProtonMail, someone else can be on AOL \u2013 yet we can all communicate back and forth because these services are using the same protocol. (Just.))\nBut that said, you could think of joining something like micro.blog as kind of like joining an \u2018Indieweb instance\u2019, and you can quite easily host your own Fediverse instance with just you on it as the sole user, so the lines are blurred.\nImplemention\nThere\u2019s more of a plurality of implementations on the Indieweb, in that a significant number of people have implemented the protocols on their site from scratch (with lots of reuse of tooling and libraries, of course). But there\u2019s also WordPress and Known implementations where you get much of the functionality out of the box. In the Fediverse, there\u2019s some flagship projects that implement ActivityPub and compatible protocols, such as Mastodon, Pleroma, Hubzilla, Pixelfed (and plenty others). But you could also build your own site and implement ActivityPub if you wanted, too.\nTo my mind, any decentralisation effort should allow you to host your own installation if you want, and build your own implementation if you want, for those that love to tinker or want maximum control; OR get an account somewhere else, with absolutely minimal effort, for those that just want to get up and running. Both types should be able to communicate with each other, not caring about where they\u2019re hosted.\nBoth the Indieweb and the Fediverse allow for both of those.\nCommunity\nThe community-aspect could have blog posts a\u2019plenty by itself too. My own hot take on it is that the greater ease of getting an account means the Fediverse is bigger and more diverse. It\u2019s a frothing hotbed of lunatic fringes (and awesome because of that). Also with that seems to come a great deal of self-reflection of general community management (content warnings, etc).\nAt present, the more P2P aspect of Indieweb makes it feel like it only has one community, itself. And that community (again, only my own observations as far as my interactions have taken me) feels very tech-oriented at present. All the great stuff happening with readers and groups might change that.\nWhy not just be on the Fediverse? Why not just be on the indieweb? Why be on both?\nPersonally speaking, I got involved with Indieweb before I found the Fediverse, and I like a number of aspects of it. I\u2019m also already part of the Fediverse, as I have an account on social.coop, and I like the people and discussions and interactions on there too. There\u2019s fun people on both, so why not be a part of both? Bridges not walls eh. I\u2019m of the opinion that different approaches help inform and improve each other; a positive symbiosis rather than a competition.\nHow to be on both\nFocusing on WordPress, there\u2019s a few different ways that I\u2019ve come across to connect the Indieweb and the Fediverse:\nPOSSEing\npterotype\nwordpress actvitypub\nbridgy fed\nPOSSE\nThe super simple way, which I currently do with my site, is the Indieweb concept of POSSEing \u2013 publish to your own site, syndicate elsewhere. When I make a post on my website, I send an additional copy to my social.coop account (and that\u2019s where I tend to get the most interaction at present.) I do this via the Mastodon Autopost plugin for indieweb and the Syndication Links plugin. One benefit of this approach for me is that I like the \u2018local\u2019 timeline of the social.coop instance, which is why I\u2019ve continued with an account there for so long. As an independent entity, I\u2019d lose some of that (unless perhaps I used a Fediverse platform that supporsed groups\u2026)\nPterotype and WordPress ActivityPub\nPterotype and WordPress ActivityPub are WordPress plugins that gives your blog an ActivityPub feed. Installing one of these plugins turns your site in to something that the rest of the Fediverse can see and follow as if you were on an instance. Other than the fact that you have a site that you own and control, these approaches are Indieweb agnostic. (Disclaimer: I haven\u2019t tried either.)\nBridgy Fed\nAnd finally there\u2019s Bridgy Fed. Bridgy is an amazing long-runnning Indieweb service that creates various bridges between Indieweb sites and other social networks. It lets you get all the benefits of the Indieweb while still having a foot in the door of the old world of Twitter, Facebook, etc. It basically translates between the Indieweb method of server-to-server communication (Webmentions), and whatever language the other networks speak. Part of this translation is also pulling back interactions from the remote networks to your own site. And Bridgy Fed does this same thing, but for the Fediverse.\nTo me, Bridgy Fed makes the most sense if you want to follow an Indieweb approach, but also want to exist on the Fediverse as an independent entity, and aren\u2019t tied to a particular instance already.\nThe post Bridging the Indieweb and the Fediverse with Bridgy Fed, part 1 appeared first on doubleloop." }, "name": "Bridging the Indieweb and the Fediverse with Bridgy Fed, part 1", "post-type": "note", "_id": "3268363", "_source": "1895", "_is_read": true }
{ "type": "entry", "published": "2019-04-29 22:42-0700", "url": "http://tantek.com/2019/119/t7/", "category": [ "IndieWeb" ], "in-reply-to": [ "https://twitter.com/voxpelli/status/1123099838197977088" ], "content": { "text": "@voxpelli you\u2019ll be missed!\nOptions:\n1. Participate remotely? We\u2019re figuring it out for Berlin & D\u00fcsseldorf!\n2. #IndieWeb Summit?\n3. Help pick dates for more 2019 IndieWebCamps! (add yourself to cities: https://indieweb.org/Planning#2019)", "html": "<a class=\"h-cassis-username\" href=\"https://twitter.com/voxpelli\">@voxpelli</a> you\u2019ll be missed!<br />Options:<br />1. Participate remotely? We\u2019re figuring it out for Berlin & D\u00fcsseldorf!<br />2. #<span class=\"p-category\">IndieWeb</span> Summit?<br />3. Help pick dates for more 2019 IndieWebCamps! (add yourself to cities: <a href=\"https://indieweb.org/Planning#2019\">https://indieweb.org/Planning#2019</a>)" }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "reply", "refs": { "https://twitter.com/voxpelli/status/1123099838197977088": { "type": "entry", "url": "https://twitter.com/voxpelli/status/1123099838197977088", "name": "@voxpelli\u2019s tweet", "post-type": "article" } }, "_id": "3238894", "_source": "1", "_is_read": true }
{ "type": "entry", "published": "2019-04-29 18:53-0700", "url": "http://tantek.com/2019/119/t2/improve-your-internethealth", "category": [ "InternetHealth", "Berlin", "D", "Utrecht", "IndieWeb" ], "content": { "text": "Read @Mozilla Internet Health Report https://internethealthreport.org/2019/ and act.\nImprove your #InternetHealth @IndieWebCamp:\n#Berlin https://2019.indieweb.org/berlin\n#D\u00fcsseldorf https://btco.nf/DUS2019indiewebcamp\n#Utrecht https://www.eventbrite.com/e/indiewebcamp-utrecht-tickets-60457184065?ref=ecount\n#IndieWeb Summit https://2019.indieweb.org/summit\n\nTravel assistance is available for the IndieWeb Summit! Apply at the sign-up link.", "html": "Read <a class=\"h-cassis-username\" href=\"https://twitter.com/Mozilla\">@Mozilla</a> Internet Health Report <a href=\"https://internethealthreport.org/2019/\">https://internethealthreport.org/2019/</a> and act.<br />Improve your #<span class=\"p-category\">InternetHealth</span> <a class=\"h-cassis-username\" href=\"https://twitter.com/IndieWebCamp\">@IndieWebCamp</a>:<br />#<span class=\"p-category\">Berlin</span> <a href=\"https://2019.indieweb.org/berlin\">https://2019.indieweb.org/berlin</a><br />#<span class=\"p-category\">D</span>\u00fcsseldorf <a href=\"https://btco.nf/DUS2019indiewebcamp\">https://btco.nf/DUS2019indiewebcamp</a><br />#<span class=\"p-category\">Utrecht</span> <a href=\"https://www.eventbrite.com/e/indiewebcamp-utrecht-tickets-60457184065?ref=ecount\">https://www.eventbrite.com/e/indiewebcamp-utrecht-tickets-60457184065?ref=ecount</a><br />#<span class=\"p-category\">IndieWeb</span> Summit <a href=\"https://2019.indieweb.org/summit\">https://2019.indieweb.org/summit</a><br /><br />Travel assistance is available for the IndieWeb Summit! Apply at the sign-up link." }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "note", "_id": "3237359", "_source": "1", "_is_read": true }
{ "type": "entry", "published": "2019-04-29 21:56-0700", "url": "http://tantek.com/2019/119/t6/improvise-offline-activities", "in-reply-to": [ "https://tantek.com/2019/119/t5/weekends-let-go-techniques" ], "content": { "text": "@voxpelli except the next two weekends are IndieWebCamps Berlin & D\u00fcsseldorf, highly in-person & online! So I\u2019ll have to improvise, perhaps more offline activities during the weekdays.", "html": "<a class=\"h-cassis-username\" href=\"https://twitter.com/voxpelli\">@voxpelli</a> except the next two weekends are IndieWebCamps Berlin & D\u00fcsseldorf, highly in-person & online! So I\u2019ll have to improvise, perhaps more offline activities during the weekdays." }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "reply", "refs": { "https://tantek.com/2019/119/t5/weekends-let-go-techniques": { "type": "entry", "url": "https://tantek.com/2019/119/t5/weekends-let-go-techniques", "name": "Tantek\u2019s note", "post-type": "article" } }, "_id": "3237355", "_source": "1", "_is_read": true }
{ "type": "entry", "published": "2019-04-29 12:46-0700", "url": "http://tantek.com/2019/119/t1/berlin-indiewebcamp-this-weekend", "category": [ "Berlin", "InternetHealth", "indieweb" ], "content": { "text": "#Berlin friends!\nJoin us @IndieWebCamp this weekend @MozillaBerlin: https://2019.indieweb.org/berlin\n\n@ioctaptceb @martijnvdven & I are looking forward to welcoming you!\n\nCC @sonniesedge @TYPOBER @TYPO_Labs @LiebeFonts @nuzz @leyink #InternetHealth #indieweb", "html": "#<span class=\"p-category\">Berlin</span> friends!<br />Join us <a class=\"h-cassis-username\" href=\"https://twitter.com/IndieWebCamp\">@IndieWebCamp</a> this weekend <a class=\"h-cassis-username\" href=\"https://twitter.com/MozillaBerlin\">@MozillaBerlin</a>: <a href=\"https://2019.indieweb.org/berlin\">https://2019.indieweb.org/berlin</a><br /><br /><a class=\"h-cassis-username\" href=\"https://twitter.com/ioctaptceb\">@ioctaptceb</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/martijnvdven\">@martijnvdven</a> & I are looking forward to welcoming you!<br /><br />CC <a class=\"h-cassis-username\" href=\"https://twitter.com/sonniesedge\">@sonniesedge</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/TYPOBER\">@TYPOBER</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/TYPO_Labs\">@TYPO_Labs</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/LiebeFonts\">@LiebeFonts</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/nuzz\">@nuzz</a> <a class=\"h-cassis-username\" href=\"https://twitter.com/leyink\">@leyink</a> #<span class=\"p-category\">InternetHealth</span> #<span class=\"p-category\">indieweb</span>" }, "author": { "type": "card", "name": "Tantek \u00c7elik", "url": "http://tantek.com/", "photo": "https://aperture-media.p3k.io/tantek.com/acfddd7d8b2c8cf8aa163651432cc1ec7eb8ec2f881942dca963d305eeaaa6b8.jpg" }, "post-type": "note", "_id": "3232797", "_source": "1", "_is_read": true }
{ "type": "entry", "author": { "name": "Neil Mather", "url": "https://doubleloop.net/", "photo": null }, "url": "https://doubleloop.net/2019/04/28/5294/", "published": "2019-04-28T15:33:18+00:00", "content": { "html": "<p>What\u2019s the best federated/distributed way to get a regular feed of solarpunk pictures (like the kind of things on <a href=\"https://solarpunk-aesthetic.tumblr.com/\">solarpunk-aesthetic.tumblr.com/</a>)?</p>\n<p>That stuff cheers me up no end and a regular dose of them in to some kind of inbox would be grand. Either fediverse or indieweb.</p>\n<p>I searched <a href=\"https://pixelfed.social/\">pixelfed.social</a> and nothing came up. </p>\n<p>#SolarPunk</p>\n<p>The post <a href=\"https://doubleloop.net/2019/04/28/5294/\">#5294</a> appeared first on <a href=\"https://doubleloop.net/\">doubleloop</a>.</p>", "text": "What\u2019s the best federated/distributed way to get a regular feed of solarpunk pictures (like the kind of things on solarpunk-aesthetic.tumblr.com/)?\nThat stuff cheers me up no end and a regular dose of them in to some kind of inbox would be grand. Either fediverse or indieweb.\nI searched pixelfed.social and nothing came up. \n#SolarPunk\nThe post #5294 appeared first on doubleloop." }, "name": "#5294", "post-type": "note", "_id": "3214170", "_source": "1895", "_is_read": true }