<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[HYVOR]]></title><description><![CDATA[Hashnode publication of HYVOR]]></description><link>https://hyvor.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 28 Oct 2026 03:41:31 GMT</lastBuildDate><atom:link href="https://hyvor.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to add a blog to Next.js using Hyvor Blogs?]]></title><description><![CDATA[This is a tutorial on how to add a blog to your Next.js application using Hyvor Blogs, an all-in-one blogging platform. We'll be adding a fully-functional…]]></description><link>https://hyvor.hashnode.dev/how-to-add-a-blog-to-nextjs-using-hyvor-blogs</link><guid isPermaLink="true">https://hyvor.hashnode.dev/how-to-add-a-blog-to-nextjs-using-hyvor-blogs</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[blog]]></category><dc:creator><![CDATA[Supun Kavinda]]></dc:creator><pubDate>Thu, 27 Jul 2023 07:28:08 GMT</pubDate><content:encoded><![CDATA[<p>This is a tutorial on how to add a blog to your <a target="_blank" href="https://nextjs.org/">Next.js</a> application using <a target="_blank" href="https://blogs.hyvor.com/">Hyvor Blogs</a>, an all-in-one blogging platform. We'll be adding a fully-functional blog with a custom theme to your Next.js app's <code>/blog</code> (you can customize this) using <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/router-handlers">Next.js Route Handlers</a>.</p>
<blockquote>
<p>This tutorial focuses on adding a "complete" blog to your app. However, if you like to create your own blog and use Hyvor Blogs only as a headless CMS, see our <a target="_blank" href="https://blogs.hyvor.com/docs/api-data">Data API</a>. (We will write a guide on this in the future)</p>
</blockquote>
<h2 id="heading-how-it-works">How it works</h2>
<p>We will use Hyvor Blogs for everything, except serving the blog. By default, your blog is hosted on a subdomain or <a target="_blank" href="http://hyvorblogs.io">hyvorblogs.io</a>. You can easily set up a custom domain like <a target="_blank" href="http://blog.mycompany.com">blog.mycompany.com</a> as well. Here, we are going to host it on <a target="_blank" href="http://mycompany.com/blog">mycompany.com/blog</a>, using Next.js Route Handlers, which will dynamically process all <code>/blog/*</code> routes.</p>
<p>When we receive a request to <code>/blog/*</code>, we'll call Hyvor Blogs <a target="_blank" href="https://blogs.hyvor.com/docs/api-delivery">Delivery API</a> to "learn" how to send a response back. Then, we will save that response in a cache so that subsequent requests can be served from the cache. Finally, we will use webhooks to clear the cache.</p>
<p>It might sound complicated, but we have abstracted most of the tasks into a library. You only have to write a couple of lines of code.</p>
<h2 id="heading-step-1-set-up-hyvor-blogs">Step 1: Set up Hyvor Blogs</h2>
<h3 id="heading-create-a-blog-amp-get-the-subdomain">Create a blog &amp; get the subdomain</h3>
<p>First, create a blog from the <a target="_blank" href="https://blogs.hyvor.com/console/new">Hyvor Blogs Console</a>. You will be asked to create a HYVOR account. Then, choose a subdomain. You will need this in the next steps.</p>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--MREx1K5q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/STa4xTVJFkUDmO1XlDAPHvjfirxI9JtaN8BhRcCa.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MREx1K5q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/STa4xTVJFkUDmO1XlDAPHvjfirxI9JtaN8BhRcCa.png" alt="Create a blog in Hyvor Blogs" /></a></p>
<h3 id="heading-change-hosting-url">Change hosting URL</h3>
<p>Next, go to Settings -&gt; Hosting, and change "Hosting At" to Self-hosting, and the URL to your self-serving URL. In this case, I am using <code>{next-app-url}/blog</code></p>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--48b5x_dW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/tw7mZ9BeklSstq0gYoW7a4woi8MvXJNfzhkhoY9h.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--48b5x_dW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/tw7mZ9BeklSstq0gYoW7a4woi8MvXJNfzhkhoY9h.png" alt="Change Hosting" /></a></p>
<blockquote>
<p>Important: To test webhooks, this URL should be publicly accessible. Therefore, if you are testing locally, use a tool like <a target="_blank" href="https://ngrok.com/">ngrok</a> to expose your next app on the internet.</p>
</blockquote>
<h3 id="heading-create-a-delivery-api-key">Create a Delivery API Key</h3>
<p>Then, go to Settings -&gt; API Keys and create a Delivery API key. You will need this in the next step.</p>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--_nsnH2YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/WAMgKOEvrIOQDyp1R0A66mqYcAPwcZDGCx6hKli7.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_nsnH2YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/WAMgKOEvrIOQDyp1R0A66mqYcAPwcZDGCx6hKli7.png" alt="Create a Delivery API key" /></a></p>
<p>Create a Delivery API key</p>
<h3 id="heading-set-up-webhook-url">Set up webhook URL</h3>
<p>Finally, go to Settings -&gt; Webhooks and create a new entry.</p>
<ul>
<li><p>URL: <code>your-app-url/blog/_hb_webhook</code></p>
</li>
<li><p>Events</p>
<ul>
<li><p><code>cache.single</code></p>
</li>
<li><p><code>cache.templates</code></p>
</li>
<li><p><code>cache.all</code></p>
</li>
</ul>
</li>
</ul>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--oXz_Soqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/12Q1frFdFlkQhOTx2ZApr5BBDM8miPOkUhe0fpYN.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oXz_Soqf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/12Q1frFdFlkQhOTx2ZApr5BBDM8miPOkUhe0fpYN.png" alt="Create a webhook" /></a></p>
<p>We'll need the Webhook Secret in the next step.</p>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--x_vp4DoP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/RgchfFocCctleFxKobjIHve7QOP5vBuuRbLZIRPy.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x_vp4DoP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/RgchfFocCctleFxKobjIHve7QOP5vBuuRbLZIRPy.png" alt="Copy webhook secret" /></a></p>
<h2 id="heading-step-2-set-up-nextjs">Step 2: Set up Next.js</h2>
<h3 id="heading-install-the-helper-library">Install the helper library</h3>
<p>We'll be using helper methods from the <a target="_blank" href="https://github.com/hyvor/hyvor-blogs-serve-web">@hyvor/hyvor-blogs-serve-web</a> library in the next steps. Install that package using your package manager.</p>
<pre><code class="lang-plaintext">npm install @hyvor/hyvor-blogs-serve-web
</code></pre>
<h3 id="heading-set-up-app-routes">Set up App Routes</h3>
<p>As mentioned earlier, we'll be using <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/routing/router-handlers">Next.js Route Handlers</a>, which comes with the app router.</p>
<p>You will need a directory structure like this:</p>
<p><a target="_blank" href="https://res.cloudinary.com/practicaldev/image/fetch/s--1PpntD-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/cDAR34K0QsBdML8SjLIk16OOHjnzKhTJyyJPhRSO.png"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1PpntD-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://hyvor.com/blog/media/cDAR34K0QsBdML8SjLIk16OOHjnzKhTJyyJPhRSO.png" alt="NextJS directory structure" /></a></p>
<pre><code class="lang-plaintext">blog
    [[..paths]]
        route.ts
</code></pre>
<blockquote>
<p>Note: <code>[[..paths]]</code> optionally matches any nested path.</p>
</blockquote>
<p>Here's the full code of <code>route.ts</code></p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Blog } <span class="hljs-keyword">from</span> <span class="hljs-string">'@hyvor/hyvor-blogs-serve-web'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBlog</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Blog({
        subdomain: <span class="hljs-string">'my-next-js-app'</span>,
        deliveryApiKey: <span class="hljs-string">'my-delivery-api-key'</span>,
        webhookSecret: <span class="hljs-string">'my-webhook-secret'</span>,
    });
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GET</span>(<span class="hljs-params">_: Request, {params}: {params: {paths: <span class="hljs-built_in">string</span>[]|<span class="hljs-literal">undefined</span>}}</span>) </span>{
    <span class="hljs-keyword">const</span> path = <span class="hljs-string">'/'</span> + (params.paths?.join(<span class="hljs-string">'/'</span>) || <span class="hljs-string">''</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> getBlog().handleBlogRequest(path);
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">POST</span>(<span class="hljs-params">request: Request, {params} : {params: {paths: <span class="hljs-built_in">string</span>[]|<span class="hljs-literal">undefined</span>}}</span>) </span>{
    <span class="hljs-keyword">if</span> (params.paths?.[<span class="hljs-number">0</span>] !== <span class="hljs-string">'_hb_webhook'</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-string">'Not Found'</span>, {status: <span class="hljs-number">404</span>});
    }
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> request.json();
    <span class="hljs-keyword">const</span> signature = request.headers.get(<span class="hljs-string">'X-Signature'</span>) || <span class="hljs-string">''</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> getBlog().handleWebhookRequest(data, signature);
}
</code></pre>
<p>Replace <code>subdomain</code>, <code>deliveryApiKey</code>, and <code>webhookSecret</code> values from the previous in the <code>getBlog()</code> function.</p>
<ul>
<li><p><code>GET</code> handles HTTP GET requests to any <code>/blog/*</code> route</p>
</li>
<li><p><code>POST</code> handles only <code>/_hb_webhook</code> path</p>
</li>
</ul>
<h3 id="heading-set-up-cache">Set up cache</h3>
<p>@hyvor/hyvor-blogs-serve-web library uses <a target="_blank" href="https://keyvhq.js.org/#/">Keyv</a> as the cache layer. By default, the cache is saved in memory. It is highly recommended to set up a custom cache (ex: Redis, Vercel KV, etc.)</p>
<p>Here is an example using Redis:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Blog({
    <span class="hljs-comment">// ...other config</span>
    cache: {
        store: <span class="hljs-keyword">new</span> KeyvRedis(<span class="hljs-string">'redis://user:pass@localhost:6379'</span>)
    }
})
</code></pre>
<p>See <a target="_blank" href="https://keyvhq.js.org/#/?id=all-the-adapters">Keyv documentation</a> for other available adapters.</p>
<p>That's all! Try visiting <code>/blog</code> path of your blog. Then, try updating one of your posts to verify that the cache is cleared using Webhooks.</p>
<h2 id="heading-finally">Finally</h2>
<p>If you have any issues, feel free to comment below.</p>
<p>Resources:</p>
<ul>
<li><p><a target="_blank" href="https://github.com/hyvor/hyvor-blogs-serve-web">Helper library on Github</a></p>
</li>
<li><p><a target="_blank" href="https://blogs.hyvor.com/docs/api-delivery">Delivery API docs</a></p>
</li>
<li><p><a target="_blank" href="https://blogs.hyvor.com/">Hyvor Blogs</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Add a blog to your Laravel Application with Hyvor Blogs]]></title><description><![CDATA[Hyvor Blogs is a simple and powerful blogging platform. In this tutorial, we will see how to create a blog with Hyvor Blogs and host it in an existing…]]></description><link>https://hyvor.hashnode.dev/add-a-blog-to-your-laravel-application-with-hyvor-blogs</link><guid isPermaLink="true">https://hyvor.hashnode.dev/add-a-blog-to-your-laravel-application-with-hyvor-blogs</guid><category><![CDATA[Laravel]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Blogging]]></category><category><![CDATA[blog]]></category><dc:creator><![CDATA[Supun Kavinda]]></dc:creator><pubDate>Thu, 15 Sep 2022 14:06:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1663250561477/2VOKuVVO7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://blogs.hyvor.com/">Hyvor Blogs</a> is a simple and powerful blogging platform. In this tutorial, we will see how to create a blog with Hyvor Blogs and host it in an existing Laravel application's <code>/blog</code> route. All contents of the blog will live inside a cache store in your application, which you can customize. We will use webhooks for cache invalidation.</p>
<h2 id="heading-part-1-set-up-hyvor-blogs">Part 1: Set up Hyvor Blogs</h2>
<p>In this part, we will create a blog and configure the basic settings needed for self-hosting.</p>
<ul>
<li><p>First, create a blog at the <a target="_blank" href="https://blogs.hyvor.com/console/new">Hyvor Blogs Console</a>. You will get a subdomain, which you need in the next step.</p>
</li>
<li><p>Go to Settings → Hosting</p>
<ul>
<li><p>Update Hosting on/at to Self-hosting</p>
</li>
<li><p>Set the Self-hosting URL to the absolute URL of your Laravel application's blog route. For this tutorial, set it to <code>https://mywebsite.com/blog</code>. You can customize the <code>/blog</code> route later if needed.</p>
<p>Note: To test webhooks, this URL should be publicly accessible. Therefore, if you are testing locally, we recommend using a tool like <a target="_blank" href="https://ngrok.com/">ngrok</a> to expose your Laravel site temporarily on the internet.</p>
</li>
<li><p>Click Save</p>
<p><img src="https://blogs.hyvor.com/blog/media/r0EILgfcGMXbVAk8FFuLXtDdprFg9BP0drwncOh2.png" alt="Hosting setting up in Hyvor Blogs Console" /></p>
</li>
</ul>
</li>
<li><p>Go to Settings → API Keys</p>
<ul>
<li><p>Click CREATE</p>
<ul>
<li><p>Set a name (ex: "For Laravel Blog")</p>
</li>
<li><p>Select Delivery API as the API</p>
</li>
<li><p>Create API Key</p>
</li>
</ul>
<p><img src="https://blogs.hyvor.com/blog/media/ymQJNm0cH1XmX0XfBnemfEGGE82HWNFvDXH1Tbxk.png" alt="Creating an API key" /></p>
</li>
</ul>
</li>
</ul>
<p>This API key will be needed in the next step.</p>
<ul>
<li><p>Go to Settings → Webhooks and create a Webhook with the following values.</p>
<ul>
<li><p>URL: Set this to "your website URL + /hyvorblogs/webhook". Ex: <code>https://mywebsite.com/hyvorblogs/webhook</code></p>
</li>
<li><p>Select the following events</p>
<ul>
<li><p><code>cache.single</code></p>
</li>
<li><p><code>cache.templates</code></p>
</li>
<li><p><code>cache.all</code></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>You will need the Webhook Secret in the next step.</p>
<h2 id="heading-part-2-set-up-laravel-application">Part 2: Set up Laravel Application</h2>
<p>In this part, we will set up your laravel application to "communicate" with Hyvor Blogs APIs/Webhooks to render your blog correctly.</p>
<p>First, install the <code>hyvor/hyvor-blogs-laravel</code> Laravel package in your project using composer.</p>
<pre><code class="lang-console">composer require hyvor/hyvor-blogs-laravel
</code></pre>
<p>Then, run the following command to generate the config file.</p>
<pre><code class="lang-console">php artisan vendor:publish --provider="Hyvor\HyvorBlogs\HyvorBlogsServiceProvider" --tag="config"
</code></pre>
<p>This command will copy the default configuration file to <code>config/hyvorblogs.php</code> in your application, where you will be configuring the blog.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">return</span> [
    <span class="hljs-string">'blogs'</span> =&gt; [
        [
            <span class="hljs-string">'subdomain'</span> =&gt; <span class="hljs-string">''</span>,
            <span class="hljs-string">'delivery_api_key'</span> =&gt; <span class="hljs-string">''</span>,
            <span class="hljs-string">'webhook_secret'</span> =&gt; <span class="hljs-literal">null</span>,
            <span class="hljs-string">'route'</span> =&gt; <span class="hljs-string">'/blog'</span>,
            <span class="hljs-string">'cache_store'</span> =&gt; <span class="hljs-literal">null</span>,
            <span class="hljs-string">'middleware'</span> =&gt; [],
        ],
    ],
];
</code></pre>
<p><code>blogs</code> key contains an array of blog configurations. It allows you to set up multiple blogs in the same Laravel application. Let's configure a blog.</p>
<ul>
<li><p>Set <code>subdomain</code> to the subdomain of the blog, you created in the first step. You can get it to Console → Settings -&gt; Hosting.</p>
</li>
<li><p>Set <code>delivery_api_key</code> to the Delivery API key, you created earlier at Console → Settings -&gt; API Keys</p>
</li>
<li><p>Set <code>webhook_secret</code> to the secret you got at Console → Settings -&gt; Webhook</p>
</li>
<li><p>Set <code>route</code> to the base path of your blog within the Laravel application. If you change this, make sure to update the Hosting URL in the Console.</p>
</li>
<li><p>(optional) Set <code>cache_store</code> to use a custom <a target="_blank" href="https://laravel.com/docs/9.x/cache">cache store</a> to cache your blog.</p>
</li>
<li><p>(optional) If you need to add any additional middleware, use the <code>middleware</code> array.</p>
</li>
</ul>
<p>Now, try visiting the <code>/blog</code> path of your blog. If everything is fine, your blog should be displayed there. Try updating a post to make sure webhooks are working.</p>
<h2 id="heading-finally">Finally</h2>
<ul>
<li><p>If you have any troubles, comment below or contact support.</p>
</li>
<li><p>If you would like to know how this works internally, see our <a target="_blank" href="https://blogs.hyvor.com/docs/self-hosting-web-framework">self-hosting with web frameworks</a> documentation.</p>
</li>
<li><p>Once you have set up everything, you can customize your blog theme and start writing. Our <a target="_blank" href="https://blogs.hyvor.com/docs">documentation</a> has all the information you need.</p>
</li>
<li><p>If you like to set up multiple blogs within the same applications, you can add more configuration arrays to the <code>blogs</code> array in the config file.</p>
</li>
<li><p>Any problems with the Laravel package? Raise an issue or contribute at <a target="_blank" href="https://github.com/hyvor/hyvor-blogs-laravel">Github</a>.</p>
</li>
</ul>
<p><em>This article was original published <a target="_blank" href="https://blogs.hyvor.com/blog/laravel">on our blog</a>.</em></p>
]]></content:encoded></item></channel></rss>