<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ cms - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ cms - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 22:38:15 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/cms/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Integrate WordPress as a Headless CMS with Next.js – With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ When building a dynamic blog website, it's common to fetch data from a content source, such as a CMS (Content Management System) like WordPress. Recently, I faced the challenge of integrating WordPress into my existing Next.js project. I had a blog h... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integrate-wordpress-with-nextjs/</link>
                <guid isPermaLink="false">66fd0d6ead9b41bdb1ef70fd</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Chidera ]]>
                </dc:creator>
                <pubDate>Wed, 02 Oct 2024 09:07:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727738740919/4dd5ea12-6e0c-4df9-8b8d-fc4f168b89c5.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building a dynamic blog website, it's common to fetch data from a content source, such as a CMS (Content Management System) like WordPress.</p>
<p>Recently, I faced the challenge of integrating WordPress into my existing Next.js project. I had a blog hosted on WordPress and wanted to migrate it to my Next.js app.</p>
<p>I needed a solution that would allow me to use WordPress as a headless CMS. The goal was simple: leverage the power of WordPress for managing content while utilizing a modern frontend framework for displaying it.</p>
<p>In this article, we’ll walk through how to integrate WordPress to a Next JS app.</p>
<h2 id="heading-why-use-a-headless-cms">Why Use a Headless CMS?</h2>
<p>A headless CMS separates the content management (back-end) from the presentation layer (front-end). This gives developers more flexibility over how content is delivered and displayed, without being restricted by traditional themes or layouts.</p>
<p>It's great for performance, and scalability, offering more control over how content is rendered on the frontend. In this case, you’ll use WordPress as your content management system but display the content in a more modern and performant way using Next.js.</p>
<h2 id="heading-what-is-nextjs">What is Next.js?</h2>
<p>If you are yet to come across Next.js, it's a powerful React-based framework that makes building optimized, server-side rendered (SSR) applications much easier.</p>
<p>It offers a bunch of features out of the box like file-based routing, API routes, static site generation (SSG), and incremental static regeneration (ISR). All these make it a great choice for creating fast, SEO-friendly websites.</p>
<h2 id="heading-how-to-connect-wordpress-and-nextjs">How to Connect WordPress and Next.js</h2>
<p>When using WordPress as a headless CMS, there are two primary ways to connect your Next.js application to your WordPress backend:</p>
<ol>
<li><p><strong>WP REST API</strong>: WordPress comes with a built-in REST API, which allows you to retrieve content from WordPress in JSON format.</p>
</li>
<li><p><strong>WPGraphQL</strong>: WordPress supports headless content management through the use of GraphQL (with plugins such as <a target="_blank" href="https://www.wpgraphql.com/">WPGraphQL</a>), making it easy to query and retrieve specific content, like blog posts, for use in a front-end framework like React.</p>
</li>
</ol>
<p>While the REST API is popular, we’ll to go with WPGraphQL because it allows for more precise queries and flexibility. With GraphQL, you can ask for exactly the data you need, which can reduce the amount of data transferred and improve performance.</p>
<h3 id="heading-steps-to-connect-wordpress-and-nextjs-using-wpgraphql">Steps to Connect WordPress and Next.js Using WPGraphQL</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727738853280/6e07d4f5-d4c7-40a8-9355-804251707593.png" alt="WPGraphQL WordPress plugin page" class="image--center mx-auto" width="739" height="529" loading="lazy"></p>
<p>The first thing you need to do is to install the WPGraphQL plugin on your WordPress site. This plugin enables GraphQL API functionality within WordPress. You can install the plugin like any other by navigating to the WordPress admin dashboard.</p>
<p>First, go to <strong>Plugins</strong> and select <strong>Add New</strong>. Then, search for <strong>WPGraphQL</strong>, and once you find it, simply install and activate the plugin.</p>
<p>After installing and activating the plugin, the GraphQL IDE will appear on the WordPress dashboard. Here, you can test various queries you may need for your frontend development.</p>
<p>Let's move on to the frontend.</p>
<h3 id="heading-how-to-fetch-data-from-wpgraphql-in-nextjs">How to Fetch Data from WPGraphQL in Next.js</h3>
<p>In your Next.js project, you'll need to fetch data from the GraphQL API. Here’s a simple example using <code>graphql-request</code>:</p>
<p>1. Install <code>graphql-request</code> to make it easy to query the GraphQL API:</p>
<pre><code class="lang-bash">npm install graphql-request
</code></pre>
<p>2. In your Next.js component, create a GraphQL query to fetch the blog posts:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> BlogHeader <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogHeader'</span>;
<span class="hljs-keyword">import</span> BlogNewsletter <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogNewsletter'</span>;
<span class="hljs-keyword">import</span> BlogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogPosts'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { request, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"graphql-request"</span>;

<span class="hljs-keyword">const</span> query = gql<span class="hljs-string">`
{
  posts(first: 10) {
    edges {
      node {
        id
        title
        excerpt
        content
        date
        author {
          node {
            id
            name            
          }
        }
        date
        slug
        featuredImage {
          node {
            sourceUrl
          }
        }
        categories {
          edges {
            node {
              name
            }
          }
        }
      }
    }
  }
}
`</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">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> posts: <span class="hljs-built_in">any</span> = <span class="hljs-keyword">await</span> request(<span class="hljs-string">'https://blog.intercity.ng/graphql'</span>, query);

    <span class="hljs-keyword">return</span> {
      props: { posts }
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching posts:'</span>, error);
    <span class="hljs-keyword">return</span> {
      props: {
        posts: []
      }
    };
  }
}

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">(<span class="hljs-params">{ posts }: { posts: <span class="hljs-built_in">any</span> }</span>) =&gt;</span> {

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"relative pb-10 pt-10 lg:pt-0 lg:mt-[-3%]"</span>&gt;
      &lt;div className=<span class="hljs-string">'t40-container w-full'</span>&gt;
        &lt;BlogHeader /&gt;
        &lt;BlogPosts posts={posts} /&gt;
        &lt;BlogNewsletter /&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index
</code></pre>
<p>In the code above, your Next.js app fetches blog posts from your WordPress backend using GraphQL and displays them on the frontend. The GraphQL query is created to retrieve post details like the title, author, content, and featured image.</p>
<p>Using Next.js <code>getStaticProps</code>, the data is fetched at build time and passed as props to the component. The blog posts are rendered through custom components like <code>BlogHeader</code>, <code>BlogPosts</code>, and <code>BlogNewsletter</code>, making the page dynamic and efficient.</p>
<p>This demonstrates how WordPress can be used as a headless CMS for a Next.js application. Now that you have successfully integrated WordPress as a headless CMS in your Next.js application, you can continue fetching more data from the GraphQL API to enhance the functionality of your app.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By using WordPress as a headless CMS and Next.js for the frontend, we can build a fast, SEO-friendly blog while taking advantage of WordPress’s powerful content management features.</p>
<p>Using WPGraphQL allowed us to efficiently fetch only the data we needed, giving us more control and improving the site's performance.</p>
<p>I hope this was useful. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Basic CMS with Google Sheets and React ]]>
                </title>
                <description>
                    <![CDATA[ In today's digital landscape, creating a content management system (CMS) that is both cost-effective and easy to maintain can be difficult, especially if you're operating on a tight budget.  This tutorial will show you a solution that leverages Googl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-basic-cms-with-google-sheets-and-reactjs/</link>
                <guid isPermaLink="false">66bdff5a0b4523e3b8b99090</guid>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ google sheets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Marco Venturi ]]>
                </dc:creator>
                <pubDate>Wed, 06 Mar 2024 17:55:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/--1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's digital landscape, creating a content management system (CMS) that is both cost-effective and easy to maintain can be difficult, especially if you're operating on a tight budget. </p>
<p>This tutorial will show you a solution that leverages Google Sheets as a makeshift database and React to build the frontend. This will let you effectively bypass the need for a dedicated server or traditional database system. </p>
<p>This approach not only reduces the overhead costs associated with web development, but also simplifies content updates and management. It's an ideal solution if you're looking to launch your own simple CMS without substantial investment.</p>
<p>This solution is suitable for freelancers at the beginning of their career and for clients who cannot invest much in their website.</p>
<h2 id="heading-why-google-sheets">Why Google Sheets?</h2>
<p>Opting for Google Sheets as the backbone of your CMS comes down to its simplicity, flexibility, and cost-effectiveness.</p>
<p>Traditional web development requires a backend server to process data, a database to store information, and a frontend to display content. But each layer adds complexity and cost. </p>
<p>Google Sheets, on the other hand, acts as a highly accessible and intuitive interface that eliminates the need for a server and a database. It lets your users update content in real-time, much like any CMS, but without the usual setup and maintenance costs. This makes it an excellent choice for individuals, small businesses, or anyone looking to deploy a web application quickly and with minimal expense. </p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Before diving into the code, ensure you have Node.js and npm installed on your system. These tools will allow us to create a React application and manage its dependencies. </p>
<p>Let's start with Google Sheets now.</p>
<h3 id="heading-step-1-set-up-your-google-sheets">Step 1: Set Up Your Google Sheets</h3>
<ol>
<li>Go to your Google Sheets</li>
<li>Open the sheet you want to use or create a new one</li>
<li>Click on <code>Extensions</code> in the menu</li>
<li>Then click on <code>Apps Script</code></li>
</ol>
<p>In the Apps Script editor, you can write a script to serve as your endpoint. Here's a script that returns the contents of a Google Sheet in JSON format:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertRangeToJson</span>(<span class="hljs-params">data</span>) </span>{
  <span class="hljs-keyword">var</span> jsonArray = [];

  <span class="hljs-comment">// Check if data is empty or doesn't contain enough rows for headers and at least one data row</span>
  <span class="hljs-keyword">if</span> (!data || data.length &lt; <span class="hljs-number">2</span>) {
    <span class="hljs-comment">// Return an empty array or a meaningful message as needed</span>
    <span class="hljs-keyword">return</span> jsonArray; <span class="hljs-comment">// or return 'No data available';</span>
  }

  <span class="hljs-keyword">var</span> headers = data[<span class="hljs-number">0</span>];
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">1</span>, length = data.length; i &lt; length; i++) {
    <span class="hljs-keyword">var</span> row = data[i];
    <span class="hljs-keyword">var</span> record = {};

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> j = <span class="hljs-number">0</span>; j &lt; row.length; j++) {
      record[headers[j]] = row[j];
    }

    jsonArray.push(record);
  }

  <span class="hljs-keyword">return</span> jsonArray;
}
</code></pre>
<p>Then:</p>
<ol>
<li>Click <code>File</code> &gt; <code>Save</code>, and give your project a name</li>
<li>Click on <code>Deploy</code> &gt; <code>New deployment</code>.</li>
<li>Click on <code>Select type</code> and choose <code>Web app</code>.</li>
<li>Fill in the details for your deployment. Under <code>Execute as</code>, choose whether the script should run as your account or as the user accessing the web app. Under <code>Who has access</code>, choose who can access your web app.</li>
<li>Click <code>Deploy</code>.</li>
</ol>
<p>You may be asked to authorize the script to access your Google Sheets. Follow the prompts to do so.</p>
<p>After deploying, you'll be given a URL for your web app. This is your API endpoint.</p>
<p>To give you an idea of what you have done so far, this is your sheet structure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Schermata-2024-03-04-alle-16.49.37.png" alt="Image" width="600" height="400" loading="lazy">
<em>How your sheet should currently look</em></p>
<p>And this is the JSON you get when you call the endpoint:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/postman_I.png" alt="Image" width="600" height="400" loading="lazy">
<em>JSON</em></p>
<h3 id="heading-step-2-create-your-react-app">Step 2: Create Your React App</h3>
<p>With your Google Sheets API ready, it's time to create the React app that will fetch and display this data.</p>
<p>First, go ahead and create a React app. Run the following command in your terminal to create a new React application:</p>
<pre><code class="lang-bash">npx create-react-app google-sheets-cards
<span class="hljs-built_in">cd</span> google-sheets-cards
npm start
</code></pre>
<p>You can also <a target="_blank" href="https://www.freecodecamp.org/news/get-started-with-vite/">use modern build tools like Vite</a> for this purpose, as CRA is no longer the recommended way of building a React app.</p>
<p>Next, create the card component. Inside the <code>src</code> directory, create a file named <code>Card.js</code>. This component will be responsible for displaying each data record:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/Card.js</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Card</span>(<span class="hljs-params">{ title, content }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{content}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Card;
</code></pre>
<p>Now it's time to fetch and display your data in App.js. Modify the <code>App.js</code> file to include logic for fetching the data from your Google Sheets API and using the Card component to display it:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/App.js</span>
<span class="hljs-keyword">import</span> React, { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Card <span class="hljs-keyword">from</span> <span class="hljs-string">'./Card'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>; <span class="hljs-comment">// Make sure to create some basic styles for the cards in App.css</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">'YOUR_ENDPOINT_URL'</span>) <span class="hljs-comment">// Replace with your actual endpoint URL</span>
      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> setData(data))
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching data:'</span>, error));
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Data from Google Sheets<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"cards-container"</span>&gt;</span>
        {data.map((item, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Card</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">title</span>=<span class="hljs-string">{item.Title}</span> <span class="hljs-attr">content</span>=<span class="hljs-string">{item.Content}</span> /&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Next, you can style your cards. Go ahead and add the below CSS in <code>App.css</code> for basic card styling:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.card</span> {
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">8px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">display</span>: inline-block;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#f9f9f9</span>;
}

<span class="hljs-selector-class">.cards-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-wrap</span>: wrap;
  <span class="hljs-attribute">justify-content</span>: center;
}
</code></pre>
<h3 id="heading-step-3-run-your-react-app">Step 3: Run Your React App</h3>
<p>With everything set up, you can now run your React application and see the data from Google Sheets displayed in your browser. To do this, follow these steps:</p>
<p>First, start the React app. In your terminal, navigate to the root directory of your React app if you're not already there. Run the following command to start the development server:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>This command compiles your React application and opens it in your default web browser. You should see a webpage with a title "Data from Google Sheets", and below that, a series of cards, each displaying a title and content fetched from your Google Sheets data. </p>
<p>Here's, in fact, what we get:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Schermata-2024-03-04-alle-16.52.22.png" alt="Image" width="600" height="400" loading="lazy">
<em>Data from Google Sheets and Card 1, Card 2, and Card 3 displayed on the screen</em></p>
<p>Now you can view your data. Each card on the page corresponds to a row in your Google Sheets, with the title and content fields displayed as specified in your Card component. If you make any updates to your Google Sheets data, you can refresh the web page to see the changes reflected immediately.</p>
<p>You can deploy your React app to one of the many services you can find online such as Github Actions or Netlify. This is a simple and effective way to host your frontend application for free with significant performance. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've created a dynamic web application that fetches data from a Google Sheet and displays it using React. </p>
<p>This approach offers a flexible and straightforward way to manage your application's content without needing a backend server or database.</p>
<p>Google Sheets serves as an accessible and collaborative platform for managing data, while React allows you to build a responsive and interactive user interface. Together, they provide a powerful combination for creating web applications that can be quickly updated and easily maintained.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose a CMS – Tips for Content Management Systems ]]>
                </title>
                <description>
                    <![CDATA[ By Scott Gary If you're an entrepreneur or a developer, chances are you'll work with a content management systems (CMS) at some point. And knowing how to analyze the many features of the CMS options out there is important when choosing the right one ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-a-cms/</link>
                <guid isPermaLink="false">66d460f2ffe6b1f641b5fa7f</guid>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Website design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 01 Jun 2023 23:06:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/how-to-choose-cms.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Scott Gary</p>
<p>If you're an entrepreneur or a developer, chances are you'll work with a content management systems (CMS) at some point. And knowing how to analyze the many features of the CMS options out there is important when choosing the right one for your use case.</p>
<p>In this article, I'll explain why CMSs exist, the problems they help solve, and I'll also offer helpful guidance in choosing the right CMS for your needs.</p>
<h2 id="heading-what-is-a-cms">What is a CMS?</h2>
<p>You can think of a CMS as an extremely user-friendly database for your website’s content.</p>
<p>A CMS provides an intuitive interface that allows website owners and content creators to manage a website's content without requiring advanced technical skills.</p>
<p>As an example, think about it from the perspective of someone who wants to own a blog, but doesn’t know anything about web development. It would be very difficult, if not impossible, for this person to modify the source code of the web site in order to add a new article to the blog.</p>
<p>This is where a CMS comes in. The CMS is linked to the owner’s website, and the site has built in code that pulls data from the CMS and automatically publishes this data on the site. In this example, the data could be a new blog article and image.</p>
<h2 id="heading-headless-cms-vs-traditional-cms">Headless CMS vs Traditional CMS</h2>
<p>You may have heard the term “headless CMS” floating around, and wondered what that was all about. Nowadays, CMSs come in two flavors; a traditional CMS, and a headless CMS. Let’s take a look at a few definitions to get a better grasp of each:</p>
<h3 id="heading-what-is-a-traditional-cms">What is a Traditional CMS?</h3>
<p>A traditional CMS is a complete website management system that not only stores your content in a user-friendly database, but also offers a front end, usually a WYSIWYG style editor to build out your actual web page. </p>
<p>The front-end UI designer and backend storage system are unified in one intuitive interface. Wordpress is a famous example of a traditional CMS.</p>
<h3 id="heading-what-is-a-headless-cms">What is a Headless CMS?</h3>
<p>A headless CMS is similar to the traditional CMS, but without the front-end WYSIWYG editor to build your site. If you think of your actual webpage as the “head”, and your content as the “body”, then this starts to make sense. </p>
<p>A headless CMS is totally independent of your site’s design, and you can typically use any framework of choice and connect it to the headless CMS. The headless CMS acts similar to a backend database, but is tailor-made for handling typically used website content like images and rich text.</p>
<h2 id="heading-when-do-i-need-a-cms">When Do I Need a CMS?</h2>
<p>Before concerning yourself with choosing the right CMS for your needs, it is essential to understand whether you actually need one. CMSs are designed to streamline the process of creating, editing, and managing digital content, primarily for websites.</p>
<p>If you’re wondering whether you should consider a CMS, ask yourself the following questions:</p>
<ol>
<li>Does the website require frequent content updates, such as articles or product listings?</li>
<li>Will there be multiple content authors collaborating on the website's content?</li>
<li>Does the website require flexible content structuring and organization to accommodate future changes?</li>
</ol>
<p>If you answered yes to one of these questions, there’s a good chance that your project would benefit from the features offered by a good CMS.</p>
<h2 id="heading-cms-integration-and-compatibility">CMS Integration and Compatibility</h2>
<p>It’s important to consider ease of integration with your chosen system or framework. You may be considering adding some functionality to your site such as an e-commerce system or customer relationship management (CRM) software. Or you may just be starting a new project from scratch.</p>
<p>Either way, it is crucial to ensure that the CMS you select can seamlessly integrate with these systems.</p>
<p>Most frameworks, such as Next.js, Gatsby or Astro, will offer a list of official CMS plugins that streamline the process of integration. Of course, a CMS can be added to any project without an official plugin by utilizing the API from your CMS of choice, and coding everything manually.</p>
<p>But it’s usually wise to look for a CMS that is supported by your framework, as it takes much of the heavy lifting out of the equation and allows you to focus on other pressing concerns.  </p>
<p>For example my blog has a list of the <a target="_blank" href="https://www.ohmycrawl.com/nextjs/best-cms/">best CMS for Next.js</a> to choose from. Most frameworks have a number of CMSs that are compatible and created by 3rd party developers.</p>
<p>When searching for a CMS with seamless integration and compatibility, look to your framework’s official docs for guidance, which should tell you what public libraries are available.</p>
<h2 id="heading-cms-features-to-consider">CMS Features to Consider</h2>
<p>When evaluating CMS options, do some research and testing rather than going for the first option that pops up. While the specific requirements may vary depending on your project, here are some fundamental features to look for:</p>
<ol>
<li><strong>User-Friendliness:</strong> The CMS should have an intuitive and user-friendly interface, enabling non-technical users to manage and update content easily. </li>
<li><strong>Content Organization:</strong> Effective content organization is crucial for a CMS. Look for features such as categorization, tagging, and metadata management to ensure your content is easily searchable and conveniently organized.</li>
<li><strong>SEO Optimization:</strong> Ensure the CMS supports essential SEO features, such as image optimization, full-featured rich text editors, and friendly URLs.</li>
</ol>
<h2 id="heading-common-cms-pitfalls">Common CMS Pitfalls</h2>
<p>There are a few potential pitfalls you should consider, because utilizing a CMS doesn’t always live up to expectations. Here are a few common challenges:</p>
<ol>
<li><strong>Overwhelming Complexity:</strong> This may seem oxymoronic, considering my earlier statement that CMSs are supposed to simplify things. But everyone is different, and one CMS may not suit your taste as much as the next person. It’s a good idea to create an account and take a look around, maybe even create some content, just to get a feel for whether the CMS is right for you.</li>
<li><strong>Hidden Costs:</strong> Many CMSs claim they are free. But almost all of them begin charging when you reach a certain threshold of traffic or storage capacity. It’s important that you do your research, and ensure that you’re considering whether your project will venture into the realm of “paid service” sooner than you expected.</li>
<li><strong>Limited Support and Documentation:</strong> When encountering issues or needing assistance, reliable support and comprehensive documentation is paramount. Ensure that the CMS you choose has an active community, official support channels, and extensive documentation or user guides. This support network can be invaluable in troubleshooting problems and learning how to make the most of the CMS's features.</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Choosing the right CMS is an important decision that can impact your website's performance, scalability, and ease of management. By understanding the purpose of a CMS and evaluating your specific needs, you can make an informed decision that aligns with your goals.   </p>
<p>Ultimately, a CMS should empower you to efficiently create, manage, and update content, allowing you to focus on delivering a compelling user experience. At the end of the day, meaningful content is the goal, and a CMS should be a helpful hand that guides you through the process.  </p>
<p>Hope you enjoyed the post. If you want to learn more about CMSs and SEO in general checkout <a target="_blank" href="https://www.ohmycrawl.com/">OhMyCrawl</a>.  If you want to follow along with one of my side projects, checkout my latest site <a target="_blank" href="http://trustingeeks.com">Trust In Geeks</a> to follow my journey.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Custom Ghost CMS Theme ]]>
                </title>
                <description>
                    <![CDATA[ Ghost CMS is a platform specifically designed for bloggers and writers. Using Ghost, you can quickly get a blog website up and running.  Ghost targets primarily writers and all the features are specifically built for writing.  Ghost's new dashboard g... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-ghost-cms-theme/</link>
                <guid isPermaLink="false">66d038a8d6e6a35e9f8e6978</guid>
                
                    <category>
                        <![CDATA[ blog ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ghost ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rajdeep Singh ]]>
                </dc:creator>
                <pubDate>Wed, 04 Jan 2023 15:20:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/ghost-theme-development-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Ghost CMS is a platform specifically designed for bloggers and writers. Using Ghost, you can quickly get a blog website up and running. </p>
<p>Ghost targets primarily writers and all the features are specifically built for writing. </p>
<p>Ghost's new dashboard gives you a user-friendly interface, and beginners can easily understand the functionality. In addition, Ghost's free tutorials will help you if you have any problems. </p>
<p><strong>Some cool Ghost features:</strong></p>
<ol>
<li>Open-source</li>
<li>Membership support</li>
<li>Rich text editor (Koenig editor)</li>
<li>Newsletters</li>
<li>Email subscriber support</li>
<li>Login functionality support</li>
<li>Integration plugin </li>
<li>Analytics dashboard</li>
<li>Inbuilt comment support</li>
<li>Inbuilt search support</li>
<li>Inbuilt search functionality</li>
<li>SEO and different types of metadata support social media</li>
<li>Custom theme design</li>
</ol>
<p>You can check out all <a target="_blank" href="https://github.com/frontendweb3/fastest">the code available for this project on GitHub here</a>.</p>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-self-hosting-vs-hosting-with-ghost">Self-Hosting vs Hosting with Ghost</a></li>
<li><a class="post-section-overview" href="#heading-what-are-the-drawbacks-of-ghost-cms">What Are the Drawbacks of Ghost?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-the-ghost-cms">How to Install the Ghost CMS</a></li>
<li><a class="post-section-overview" href="#heading-understanding-the-ghost-folder-structure">Understanding the Ghost Folder Structure</a></li>
<li><a class="post-section-overview" href="#heading-understanding-the-ghost-theme-folder-structure">Understanding the Ghost Theme Folder Structure</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-new-theme-with-the-npm-cli-tool">How to Create a New Theme with the npm CLI Tool</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-new-ghost-theme-from-scratch">How to Create a New Ghost Theme from Scratch</a></li>
<li><a class="post-section-overview" href="##how-to-install-ghost-cli-globally">How to Install ghost-cli Globally</a></li>
<li><a class="post-section-overview" href="#heading-how-to-install-ghost-locally">How to install Ghost locally</a></li>
<li><a class="post-section-overview" href="#heading-how-to-configure-tailwind-css">How to Configure Tailwind CSS</a></li>
<li><a class="post-section-overview" href="#heading-other-important-commands-in-the-ghost-cli">Other Important Commands in the Ghost CLI</a></li>
<li><a class="post-section-overview" href="#how-to-write-the-code-for-our-custom-ghost-theme">How to Write the Code for Our Custom Ghost Theme</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-theme-configuration-in-packagejson">How to add theme configuration in package.json</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-theme-helpers">How to Use Theme Helpers</a></li>
<li><a class="post-section-overview" href="#heading-what-is-the-partials-folder">What is the Partials Folder?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-default-page">How to Create a Default Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-an-index-page">How to Create an Index Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-posts-page">How to Create a Posts Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-informational-pages">How to Create Information Pages</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-an-author-page">How to Create an Author Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-tags-page">How to Create a Tags Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-an-error-page">How to Create an Error Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-enable-comments">How to Enable Comments</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-search">How to Set Up Search</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-self-hosting-vs-hosting-with-ghost">Self-hosting vs Hosting with Ghost</h2>
<p>Ghost provides two ways to create/host your website:</p>
<ol>
<li>Self-hosting</li>
<li>With the Ghost cloud platform</li>
</ol>
<h3 id="heading-self-hosting">Self-hosting</h3>
<p>If you choose to self-host, you'll host your website on any cloud platform like <a target="_blank" href="https://cloud.google.com/">Google cloud</a>, <a target="_blank" href="https://aws.amazon.com/">AWS cloud,</a> <a target="_blank" href="https://azure.microsoft.com/">Azure cloud</a>, <a target="_blank" href="https://www.digitalocean.com/">Digital Ocean</a>, and so on. These are some of the most used cloud platforms in the market. </p>
<p>Most cloud platforms come with one click to deploy solutions. This means you can deploy your Ghost blog with a single click. </p>
<p>Before deploying your Ghost blog, you should compare all cloud platforms based on pricing before choosing one.  </p>
<p>Self-hosting your Ghost blog is free, and you do not need to pay anything to the Ghost platform. You'll just pay your cloud provider. </p>
<h3 id="heading-hosting-with-the-ghost-cloud-platform">Hosting with the Ghost Cloud Platform</h3>
<p>If you choose to host with Ghost, they'll help create the blog and host it on the Ghost platform itself. The Ghost team handles all the maintenance and security. You won't have to worry about updating Ghost and any themes you're using – the Ghost staff will handle that for you.</p>
<p>Self-hosting focuses more on developers, while hosting with the Ghost platform targets anyone who doesn't know about computers and programming.</p>
<p>Ghost hosting comes with a paid plan – it's not free. But they give you 14 day free trial period, after which you shift automatically into a paid plan.</p>
<h3 id="heading-what-should-you-choose-paid-or-self-hosting">What should you choose, paid or self-hosting?</h3>
<p>In my experience, hosting with the Ghost platform is the best solution for beginner developers, non-developers, and writers. The Ghost team handles everything for you. You do not worry about traffic, security, or maintenance and do not need to update the Ghost CMS. This lets you focus on writing. </p>
<p>As a developer, I always recommended that you self-host Ghost. I have run my self-hosted Ghost blog with Google Cloud for two years with a Bitnami one-click deployment.</p>
<p>After six months, I'd used up my $200 free credit, and then I started to pay monthly to Google Cloud hosting.</p>
<p>For a non-technical person, I highly recommended using the Ghost (pro) cloud platform and as well any other platform that provides Ghost-based cloud and shares hosting.</p>
<p>I found a <a target="_blank" href="https://geekflare.com/ghost-hosting-platforms/">list of Ghost-hosting platforms</a> on the internet. Perhaps one of these will solve your hosting issues or questions. If you plan to deploy Ghost with the G<a target="_blank" href="https://officialrajdeepsingh.dev/tags/ghost-cms/">oogle Cloud platform</a>, I have an article on that.</p>
<h2 id="heading-what-are-the-drawbacks-of-ghost-cms">What are the Drawbacks of Ghost CMS?</h2>
<p>The biggest drawback of Ghost is that web performance can feel slow. If you want good web performance, you'll likely need to use a CDN for media (images, videos, and PDFs) and also for CSS and JavaScript.  </p>
<p>The second biggest drawback is cost. I've been running my blog with Ghost for two years, and I pay 10 to 20 times extra to Google Cloud for hosting as a self-deploy. </p>
<p>My website has 4000 to 5000 active monthly users, and I pay 20 times extra. Because of this, I shifted my website to Hugo. </p>
<p>Now I still have 4000 to 5000 active users on the website, and I pay zero money to Netlify.</p>
<h3 id="heading-the-solution-for-developers">The Solution for Developers</h3>
<p>The best solution for developers is to use Ghost as a backend and, with the REST API, choose any JavaScript framework like Next.js, Fresh, Astro, and so on. </p>
<p>There are a lot of frameworks that can help you build a static website. In addition, static websites are fast and deploy with zero JavaScript.</p>
<p>In this method, you may not use all Ghost's features, but you can save a lot of money. Still, building the website with a JavaScript framework takes a lot of time just to run the essential version of the website. </p>
<p>My solution only works well for a small team. So if your team has a lot of writers and submits many articles in a single day, I'd recommend sticking with Ghost CMS as a frontend and backend.</p>
<p>Ghost version 5.0 is 20% faster than the old version. Suppose you use Ghost and want to design your own custom theme – then this article is for you. Let's get started.</p>
<h2 id="heading-how-to-install-the-ghost-cms">How to Install the Ghost CMS</h2>
<p>How you install Ghost CMS changes according to your operating system. We'll discuss installation for all operating systems in this guide. You can install Ghost with npm, yarn, and Docker.</p>
<p>Now let's look at how to install Ghost for:</p>
<ol>
<li>Windows, Linux, and macOS</li>
<li>Docker image</li>
</ol>
<h2 id="heading-how-to-install-ghost-on-windows-linux-and-macos">How to Install Ghost on Windows, Linux, and macOS</h2>
<p>Setting up the Ghost theme development environment in Windows and macOS is a straightforward process. But it's best if you've installed the npm or yarn package manager. If you don't have Node.js, npm, and yarn, yolu'll need to install them – Node.js comes with preinstalled npm and yarn. </p>
<p>To install Ghost CMS globally and locally, follow these basic steps:</p>
<h3 id="heading-how-to-install-ghost-cli-globally">How to install ghost-CLI globally</h3>
<p>First, you can install <code>ghost-cli</code> globally on your machine using npm or yarn. Here are the commands:</p>
<pre><code class="lang-bash">npm install ghost-cli@latest -g
    OR
yarn global add ghost-cli@latest
</code></pre>
<h3 id="heading-how-to-install-ghost-locally">How to install Ghost locally</h3>
<p>Next, when your ghost-CLI installation is complete, then run the <code>ghost local</code> command in your terminal. It looks like this:</p>
<pre><code class="lang-bash">ghost install <span class="hljs-built_in">local</span>
</code></pre>
<p>The command output looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/carbon--1-.png" alt="Ghost cms folder structure" width="600" height="400" loading="lazy">
<em>Ghost cms folder structure</em></p>
<p><strong>Note</strong>: you'll need to run the <code>ghost install local</code> command in an empty folder. Otherwise, you'll face an error:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ghost-not-empty-error.png" alt="Not empty directory error with ghost-cli" width="600" height="400" loading="lazy">
<em>Not empty directory error with ghost-cli</em></p>
<p>To start the local development server, run the <code>ghost start</code> command in your terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ghost-start-command.png" alt="Ghost start command " width="600" height="400" loading="lazy">
<em>Ghost start command</em></p>
<p>If you get an error when running <code>ghost start</code> in Ubuntu, run the following command: <code>ghost start --no-setup-linux-user</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/not-readable-by-other-user.png" alt="The directory is not readable by other users' errors in ghost cms." width="600" height="400" loading="lazy">
<em>The directory is not readable by other users' error in Ghost CMS.</em></p>
<h2 id="heading-how-to-set-up-your-environment-using-a-docker-image">How to Set Up Your Environment Using a Docker Image</h2>
<p>Docker is also a great way to set up a theme development or production environment for Ghost. The Ghost team provides an official <a target="_blank" href="https://hub.docker.com/_/ghost">Ghost Docker image</a> on Docker Hub. </p>
<p>To start the setup, you'll need the <code>docker-compose.yml</code> file in your root project folder. Then run the <code>docker-compose up</code> command in your terminal. </p>
<pre><code>version: <span class="hljs-string">'3.8'</span>
<span class="hljs-attr">services</span>:
  blog:
    image: ghost
    <span class="hljs-attr">restart</span>: always
    <span class="hljs-attr">ports</span>:
      - <span class="hljs-number">8080</span>:<span class="hljs-number">2368</span>
    <span class="hljs-attr">volumes</span>:
      - ./custom-ghost-theme:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/custom-ghost-theme/
    environment:
      url: http:<span class="hljs-comment">//localhost:808</span>
      NODE_ENV: development
</code></pre><p>In the volume section, you pass your file. In my case, I added a specific file in my Ghost theme folder.</p>
<pre><code>version: <span class="hljs-string">'3.8'</span>
<span class="hljs-attr">services</span>:
  blog:
    image: ghost
    <span class="hljs-attr">restart</span>: always
    <span class="hljs-attr">ports</span>:
      - <span class="hljs-number">8080</span>:<span class="hljs-number">2368</span>
    <span class="hljs-attr">volumes</span>:
      - ./assets:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/assets
      - ./partials:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/partials
      - ./author.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/author.hbs
      - ./<span class="hljs-keyword">default</span>.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/<span class="hljs-keyword">default</span>.hbs
      - ./error<span class="hljs-number">-404.</span>hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/error<span class="hljs-number">-404.</span>hbs
      - ./error.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/error.hbs
      - ./gulpfile.js:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/gulpfile.js
      - ./index.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/index.hbs
      - ./package-lock.json:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/package-lock.json
      - ./package.json:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/package.json
      - ./page.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/page.hbs
      - ./post.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/post.hbs
      - ./query.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/query.hbs
      - ./tag.hbs:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/tag.hbs
      - ./readme.md:<span class="hljs-regexp">/var/</span>lib/ghost/content/themes/fastest/readme.md
    <span class="hljs-attr">environment</span>:
      url: http:<span class="hljs-comment">//localhost:8080</span>
      NODE_ENV: development
</code></pre><p>In your custom-ghost-theme folder, you need the <code>index.hbs</code>, <code>post.hbs</code>, and <code>package.json</code> files to start theme development. But, you'll get an error when you activate your theme in the Ghost dashboard without requiring a file.</p>
<p><strong>Here's the GitHub repo if you want to follow along:</strong></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/officialrajdeepsingh/ghostthemewithdocker">https://github.com/officialrajdeepsingh/ghostthemewithdocker</a></div>
<h4 id="heading-errors">Errors</h4>
<p>In Ubuntu (22.04) or any other Linux distros, you'll get the <code>Message: The directory /home/rajdeepsingh/ is not readable by other users on the system</code> error. This means yours is old. So update your <code>ghost-cli</code> then run the <code>ghost start</code> command in your folder.</p>
<h2 id="heading-understanding-the-ghost-folder-structure">Understanding the Ghost Folder Structure</h2>
<p>The Ghost folder structure has three main folders and one file. They are:</p>
<ol>
<li>The <code>config.development.json</code> file contains the configuration for Ghost development.</li>
<li>The <code>current</code> folder is a link (symbolic link) that targets the install version.</li>
<li>The <code>version</code> folder contains all versions of Ghost cms.</li>
<li>The content folder is the main folder containing our database file, settings, theme, images, media, and so on.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ghost-folder-sturture.png" alt="Ghost cms folder Structure" width="600" height="400" loading="lazy">
<em>Ghost CMS folder Structure</em></p>
<p>The folder structure might change according to the operating system but the <code>content</code> folder is the same in every operating system.</p>
<p>The content folder contains all the important files for Ghost.  They are:</p>
<ol>
<li>The data folder contains an SQLite3 database file. Ghost, by default, uses the SQLite3 database.</li>
<li>Files, images, and media folders contain all files which writers upload.</li>
<li>The public folder contains all public CSS and JavaScript files – for example, card and member JavaScript and CSS files.</li>
<li>Finally, the settings folder contains all the settings, for example, the <code>router.xml</code> file.</li>
<li>The theme folder contains all files and folders used to develop the theme.</li>
</ol>
<h2 id="heading-understanding-the-ghost-theme-folder-structure">Understanding the Ghost Theme Folder Structure</h2>
<p>You can build a new custom theme store in the <code>content/theme</code> folder. To develop a new theme, you'll always need to create a new folder with the theme name and store all files in the theme name folder.</p>
<pre><code><span class="hljs-comment">// theme structure</span>

content 
content/theme
content/theme/my-theme-name
content/theme/my-theme-name/index.hbs
content/theme/my-theme-name/post.hbs
content/theme/my-theme-name/package.json

<span class="hljs-comment">// rest of file created in my-theme-name folder</span>
</code></pre><p>Ghost CMS uses <strong>handlebars</strong> to build a Ghost theme. There are a number of files but only three files are required:</p>
<ol>
<li><code>index.hbs</code> in the main file (required) to design the home page of the website.</li>
<li><code>post.hbs</code> the file (required)  is used to read and design the full article.</li>
<li><code>package.json</code> file (required)  is used for Node.js config, and it also uses the theme name, description, version, custom config, and so on.</li>
<li>The <code>default.hbs</code> file is used to build the layout of the theme.</li>
<li>The assets folder contains all the JavaScript, CSS, fonts, and image files.</li>
<li>The partials folder helps divide files into small partials (parts) for better code readability.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/theme-struture.png" alt="Ghost theme folder structure" width="600" height="400" loading="lazy">
<em>Ghost theme folder structure</em></p>
<h2 id="heading-how-to-create-a-new-theme-with-the-npm-cli-tool">How to Create a New Theme with the npm CLI Tool</h2>
<p>The easiest way to start a new Ghost theme is with the <a target="_blank" href="https://www.npmjs.com/package/create-ghost-theme">create-ghost-theme CLI</a>. I built it, and I maintain it. The create-ghost-theme CLI helps you create the following folder structure that we'll discuss next. But currently, it only supports <strong>Tailwind CSS</strong>. </p>
<p>First, we'll create a new theme with the create-ghost-theme CLI and restart the Ghost CMS local server again.</p>
<h3 id="heading-folder-structure">Folder structure</h3>
<p>After creating a new theme with <a target="_blank" href="https://www.npmjs.com/package/create-ghost-theme">create-ghost-theme CLI</a>, your folder structure looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/ghost-theme-cli.png" alt="create-ghost-theme cli folder structure" width="600" height="400" loading="lazy">
<em>create-ghost-theme cli folder structure</em></p>
<h3 id="heading-understanding-the-new-website-layout">Understanding the New Website Layout</h3>
<p>After creating the theme with create-ghost-theme CLI, your theme looks like this. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/default-hbs.png" alt="Image" width="600" height="400" loading="lazy">
<em>index.hbs</em></p>
<p>Your website reading page will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/index-hbs.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Your new tag page looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/tag-hbs.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-create-a-new-ghost-theme-from-scratch">How to Create a New Ghost Theme from Scratch</h2>
<p>When you're learning about Ghost theme development, my recommendation is to start creating a new theme from scratch. Then you can use the CLI tool I just showed you. This will be a lot easier for you.</p>
<p>So now, that's what we're going to cover in-depth: how to create a new Ghost CMS theme from scratch. </p>
<h3 id="heading-requirements">Requirements:</h3>
<p>To create a new theme, you'll need two libraries: the first is <code>ghost-cli</code> and the second is Tailwind CSS. </p>
<p>Here's what we'll go over in the coming sections:</p>
<ol>
<li>How to install <code>Ghost-cli</code> globally</li>
<li>How to configure Tailwind CSS</li>
<li>How to understand more commands in the Ghost CLI</li>
<li>Finally, we'll write the code</li>
</ol>
<h3 id="heading-how-to-install-ghost-cli-globally-1">How to Install ghost-cli Globally</h3>
<p>We went over how to do this above, but in case you need a reminder here it is:</p>
<p>First, you can install <code>ghost-cli</code> globally on your machine using npm or yarn. Here are the commands:</p>
<pre><code class="lang-bash">npm install ghost-cli@latest -g
    OR
yarn global add ghost-cli@latest
</code></pre>
<h3 id="heading-how-to-configure-tailwind-css">How to Configure Tailwind CSS</h3>
<p>Tailwind CSS is a powerful CSS library for designing the front end of a website. And you can easily use it with Ghost.</p>
<p>Install Tailwind CSS in your theme folder like this:</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
</code></pre>
<p>After Tailwind and another package have been successfully installed, then run the following command to configure Tailwind for your theme development:</p>
<pre><code class="lang-bash">npx tailwindcss init
</code></pre>
<p>The <code>tailwindcss init</code> command creates a <code>tailwind.config.js</code> file. Here's what you'll see:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
<span class="hljs-attr">content</span>: [],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Config your template path in the content section, so Tailwind CSS tracks the CSS classes. Then compile those classes in the production file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [<span class="hljs-string">"*.hbs"</span>,<span class="hljs-string">"partials/*.hbs"</span>],
  <span class="hljs-attr">darkMode</span>: <span class="hljs-string">'class'</span>,
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Create a <code>main.css</code> or <code>dev.css</code> and use any other file name to create the file for Tailwind directives. Then paste the following tailwind CSS directives code into the file:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Create the script for Tailwind CSS to check all the classes then create a production-ready CSS file for your theme. </p>
<pre><code class="lang-json">    <span class="hljs-string">"scripts"</span>: {
        <span class="hljs-attr">"start"</span>: <span class="hljs-string">"npx tailwindcss -i ./assets/css/dev.css -o ./assets/build/css/build.css --watch"</span>
    },
</code></pre>
<p>The last step is to link the production-ready CSS file to your theme like this:</p>
<pre><code class="lang-handlebars">&lt;head&gt;
    {{!-- link production ready css file  --}}
    &lt;link rel="stylesheet" href="{{asset 'build/css/build.css'}}" /&gt;
&lt;/head&gt;
</code></pre>
<p>The one problem you might face when you enable Tailwind CSS in a Ghost theme is that refreshing your site in the development process is manual. When you change anything related to Tailwind classes, you'll need manually refresh your website again. I haven't found a solution yet, but you can use the live server for that for now.</p>
<h3 id="heading-other-important-commands-in-the-ghost-cli">Other Important Commands in the Ghost CLI</h3>
<p>There are a number of other commands you'll use often when working in the Ghost CLI. Let's go through them now. Here's what we'll discuss:</p>
<ol>
<li>ghost stop</li>
<li>ghost ls</li>
<li>ghost doctor</li>
<li>ghost uninstall</li>
<li>ghost version</li>
<li>ghost restart</li>
<li>ghost update</li>
<li>ghost version</li>
<li>ghost --help</li>
</ol>
<h4 id="heading-how-to-use-the-ghost-stop-command">How to use the ghost stop command</h4>
<p>The <code>ghost stop</code> command stops the currently running instance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-stop.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-ls-command">How to use the ghost ls command</h4>
<p>The <code>ghost ls</code> command prints the current installs instance list in your machine.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-ls.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-doctor-command">How to use the ghost doctor command</h4>
<p>The <code>ghost doctor</code> command checks the system's health to see if everything is fine before running the <code>ghost install</code> or <code>ghost update</code> command. </p>
<p>If you face any errors in Ghost, you can also use the ghost doctor command to check the errors.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-doctor.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-uninstall-command">How to use the ghost uninstall command</h4>
<p>The <code>ghost uninstall</code> command removes the Ghost instance and related configuration files as well.</p>
<h4 id="heading-how-to-check-the-ghost-version">How to check the Ghost version</h4>
<p>You can use the <code>ghost version</code> command to check your currently installed version of Ghost.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-version.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-restart-command">How to use the ghost restart command</h4>
<p>The <code>ghost restart</code> command restarts your currently running Ghost instance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-restart.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-update-command">How to use the ghost update command</h4>
<p>The ghost update command updates your old Ghost version to the new version.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost-update.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-use-the-ghost-help-command">How to use the ghost --help command</h4>
<p>The <code>ghost --help</code> command prints a help page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/ghost---help.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-finally-well-write-the-code">Finally, we'll write the code</h3>
<p>Now we get to start writing the code. Here's what we'll cover in the coming sections:</p>
<ol>
<li>How to add theme configuration in <code>package.json</code> [required]</li>
<li>How to use theme helpers</li>
<li>What is the partials folder?</li>
<li>How to create a default page</li>
<li>How to create an index page [required]</li>
<li>How to create a posts page [required]</li>
<li>How to create informational page</li>
<li>How to create a tags page</li>
<li>How to set up comments</li>
<li>How to enable search</li>
</ol>
<h3 id="heading-how-to-add-theme-configuration-in-packagejson">How to add theme configuration in package.json</h3>
<p>The <code>package.json</code> file is the main file where you add or change the theme name, description, and custom configuration for the theme. </p>
<p>The <strong>first step</strong> is to create <code>package.json</code> file and add the theme name, description, version, and additional configuration. </p>
<p>The following properties are used by Ghost themes: <code>name</code>, <code>description</code>, <code>version</code>, <code>engines</code>, <code>card_assets</code>, <code>license</code>, <code>author</code>, <code>keywords</code>, <code>screenshots</code>, and <code>config</code> in the <code>package.json</code> file. </p>
<p>The most important properties are <code>name</code>, <code>description</code>, <code>version</code>,  <code>engines</code>, <code>card_assets</code>, and <code>config</code>. Here's what this looks like in the code:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"fastest"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Fastest ghost cms base theme. Fastest is light weight, modern open-source theme"</span>,
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.7"</span>,
    <span class="hljs-attr">"engines"</span>: {
        <span class="hljs-attr">"ghost"</span>: <span class="hljs-string">"&gt;=5.0.0"</span>
    },
    <span class="hljs-attr">"license"</span>: <span class="hljs-string">"MIT"</span>,
    <span class="hljs-attr">"scripts"</span>: {
        <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"gulp"</span>,
        <span class="hljs-attr">"start"</span>: <span class="hljs-string">"npx tailwindcss -i ./assets/css/dev.css -o ./assets/build/css/build.css --watch"</span>
    },
    <span class="hljs-attr">"author"</span>: {
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Rajdeep Singh"</span>,
        <span class="hljs-attr">"email"</span>: <span class="hljs-string">"officialrajdeepsingh@gmail.com"</span>,
        <span class="hljs-attr">"url"</span>: <span class="hljs-string">"https://officialrajdeepsingh.dev"</span>
    },
    <span class="hljs-attr">"keywords"</span>: [
        <span class="hljs-string">"ghost"</span>,
        <span class="hljs-string">"theme"</span>,
        <span class="hljs-string">"blog"</span>,
        <span class="hljs-string">"light weight"</span>,
        <span class="hljs-string">"ghost-theme"</span>
    ],
    <span class="hljs-attr">"screenshots"</span>: {
        <span class="hljs-attr">"desktop"</span>: [
            <span class="hljs-string">"assets/dark.png"</span>,
            <span class="hljs-string">"assets/light.png"</span>
        ],
        <span class="hljs-attr">"mobile"</span>: <span class="hljs-string">"assets/mobile.png"</span>
    },
    <span class="hljs-attr">"config"</span>: {
        <span class="hljs-attr">"posts_per_page"</span>: <span class="hljs-number">10</span>,
        <span class="hljs-attr">"card_assets"</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">"image_sizes"</span>: {},
        <span class="hljs-attr">"custom"</span>: {
            <span class="hljs-attr">"linkedin_url"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"text"</span>,
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"None"</span>
            },
            <span class="hljs-attr">"github_url"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"text"</span>,
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"None"</span>
            },
            <span class="hljs-attr">"instagram_url"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"text"</span>,
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"None"</span>
            },
            <span class="hljs-attr">"copyright"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"text"</span>,
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"Copy right by Rajdeep Singh"</span>
            },
            <span class="hljs-attr">"copyright_url"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"text"</span>,
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"https://officialrajdeepsingh.dev/pages/terms-and-conditions/"</span>
            },
            <span class="hljs-attr">"adsense_enable"</span>: {
                <span class="hljs-attr">"type"</span>: <span class="hljs-string">"select"</span>,
                <span class="hljs-attr">"options"</span>: [
                    <span class="hljs-string">"Disable"</span>,
                    <span class="hljs-string">"Enable"</span>
                ],
                <span class="hljs-attr">"default"</span>: <span class="hljs-string">"Disable"</span>
            }
        }
        },
    <span class="hljs-attr">"devDependencies"</span>: {
        <span class="hljs-attr">"@tailwindcss/typography"</span>: <span class="hljs-string">"^0.5.8"</span>,
        <span class="hljs-attr">"autoprefixer"</span>: <span class="hljs-string">"^10.4.13"</span>,
        <span class="hljs-attr">"cssnano"</span>: <span class="hljs-string">"^5.0.17"</span>,
        <span class="hljs-attr">"gscan"</span>: <span class="hljs-string">"^4.22.0"</span>,
        <span class="hljs-attr">"gulp"</span>: <span class="hljs-string">"4.0.2"</span>,
        <span class="hljs-attr">"gulp-autoprefixer"</span>: <span class="hljs-string">"^8.0.0"</span>,
        <span class="hljs-attr">"gulp-concat"</span>: <span class="hljs-string">"^2.6.1"</span>,
        <span class="hljs-attr">"gulp-cssnano"</span>: <span class="hljs-string">"^2.1.3"</span>,
        <span class="hljs-attr">"gulp-livereload"</span>: <span class="hljs-string">"4.0.2"</span>,
        <span class="hljs-attr">"gulp-sourcemaps"</span>: <span class="hljs-string">"^3.0.0"</span>,
        <span class="hljs-attr">"gulp-uglify"</span>: <span class="hljs-string">"^3.0.2"</span>,
        <span class="hljs-attr">"postcss"</span>: <span class="hljs-string">"^8.4.20"</span>,
        <span class="hljs-attr">"tailwindcss"</span>: <span class="hljs-string">"^3.2.4"</span>
    }
}
</code></pre>
<p>You can learn more about <a target="_blank" href="https://ghost.org/docs/themes/content/">card_assets</a> and <a target="_blank" href="https://ghost.org/docs/themes/structure/#packagejson">config</a> for the theme. The config section helps add configuration for Ghost. You can also add more <a target="_blank" href="https://ghost.org/docs/themes/custom-settings/">custom configuration</a> for Ghost and enable and disable it with the Ghost UI. </p>
<p>To check all configurations, go to Ghost &gt; Settings &gt; Design &gt; and click Site-wide. There you can check all configuration lists provided by the theme developer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/customconfig.png" alt="custom config enable and disable in ghost cms" width="600" height="400" loading="lazy">
<em>custom config enable and disable in ghost cms</em></p>
<h3 id="heading-how-to-use-theme-helpers">How to Use Theme Helpers</h3>
<p>The Ghost team provide lots of helpful functions to add additional functionality to the Ghost theme with <a target="_blank" href="https://handlebarsjs.com/">handlebars</a>. Some of the functionality by default comes with handlebars and other functionality is built by the Ghost team and maintained by the community.  </p>
<p>The Ghost team uses handlebars to build the entire Ghost CMS and theme. Basically, handlebars.js is a template language that helps you build both static and dynamic websites. </p>
<p>There are lots of Ghost helpers like <a target="_blank" href="https://ghost.org/docs/themes/helpers/foreach/">foreach</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/get/">get</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/if/">if</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/is/">is</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/match/">match</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/config/">@config</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/comments/">comments</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/navigation/">navigation</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/post/">post</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/total_members/">total_members</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/total_paid_members/">total_paid_members</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/block/">block</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/asset/">asset</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/ghost_head_foot/">ghost_head</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/ghost_head_foot/">ghost_foot</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/pagination/">pagination</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/partials/">partials</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/body_class/">body_class</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/block/">block</a>, <a target="_blank" href="https://ghost.org/docs/themes/helpers/search/">search</a> and many more. </p>
<p>You can read about all of the <a target="_blank" href="https://ghost.org/docs/themes/helpers/">helpers on the official docs</a>. You can also copy-paste some of the code so you do not need to remember. </p>
<h3 id="heading-what-is-the-partials-folder">What is the Partials Folder?</h3>
<p>The partials folder is like a component folder where you define all components for your theme. Basically, components are reusable code that you can reuse as often as you need. In the theme structure, we call these partials. All the partials are created with handlebars.js.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/partials.png" alt="partials for ghost theme" width="600" height="400" loading="lazy">
<em>partials for ghost theme</em></p>
<p>I create more than 24 partials for my Ghost theme and you can easily reuse them across websites. You can use partials with the following syntax: <code>{{&gt; your-partials-file-name}}</code>.</p>
<h3 id="heading-how-to-create-a-default-page">How to Create a Default Page</h3>
<p>First, we need to built a <code>default.hbs</code> file. The <code>default.hbs</code> file helps us build a layout for the website. Here's the code:</p>
<pre><code class="lang-handlebars">&lt;!DOCTYPE html&gt;

&lt;html class="dark scroll-smooth overflow-x-hidden" lang="{{@site.locale}}"&gt;

&lt;head&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;

    {{!-- link production ready css file  --}}
    &lt;link rel="stylesheet" href="{{asset 'build/css/build.css'}}" /&gt;
   {{!-- ghost header --}}
      {{ghost_head}}

&lt;/head&gt;


&lt;body class="{{body_class}} bg-white dark:bg-slate-800 dark:text-white antialiased scroll-smooth "&gt;

  {{!-- partials/header --}}
    {{&gt; header}}

    &lt;main class="mt-6 flex flex-col"&gt;

{{!-- Render other pages  --}}
        {{{body}}}

    &lt;/main&gt;
{{!-- partials/footer --}}
    {{&gt; footer}}
    {{&gt; banner}}

{{!-- ghost header --}}
    {{ghost_foot}}

    &lt;script src="{{asset 'build/js/main.js'}}"&gt;&lt;/script&gt;

&lt;/body&gt;

&lt;/html&gt;
</code></pre>
<p>Let's see what's going on here:</p>
<ol>
<li><code>{{meta_title}}</code> provides the title from the website.</li>
<li>The <code>@site</code> is a global variable and you can access a title with <code>{{@site.title}}</code>. </li>
<li>Include a Ghost <code>{{ghost_head}}</code> in the head tag.</li>
<li>Include a Ghost <code>{{ghost_foot}}</code> in the footer tag.</li>
<li>Inserted all other templates with the <code>{{{body}}}</code> tag in index.hbs, post.hbs, and so on.</li>
<li>All other templates get inserted in index.hbs, post.hbs, and so on.</li>
<li>Include dynamic CSS classes with <code>{{body_class}}</code> in the <code>&lt;body&gt;</code> tag</li>
<li>Add footer partials in the default <code>{{&gt; footer}}</code> file</li>
<li>Add header partials in default <code>{{&gt; header}}</code> file</li>
<li>Include assets from the <code>{{asset "build/tailwind.css"}}</code> folder.</li>
</ol>
<h3 id="heading-how-to-create-an-index-page">How to Create an Index Page</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/index.png" alt="Create index.hbs in the ghost theme" width="600" height="400" loading="lazy">
<em>Create <code>index.hbs</code> in the Ghost theme</em></p>
<p>The index page is the main page of the website. You can create a similar index page with the following code:</p>
<pre><code class="lang-handlebars">{{!--  Add default.hbs layout file --}}
{{!&lt; default}} 

{{!-- loop all the posts and show on home page --}}

{{#foreach posts}} 

{{!--  check condition defined in config section in package.json and add adsense code after every third post --}}
    {{#has number="nth:3" }} 
        {{#match @custom.adsense_enable "Enable" }} 
            {{&gt; ads}}
        {{/match}}
    {{/has}}

    {{!-- partials/postCard.hbs --}}
    {{&gt; postCard }}

    {{/foreach}}

    {{!-- Add pagination --}}
    {{pagination}}

{{!--  check condition defined in config section in package.json and add adsense --}}
    {{#match @custom.adsense_enable "Enable"}}
        {{&gt; ads}}
    {{/match}}

{{!-- newsletter partials --}}
    {{&gt; newsletter}}
</code></pre>
<p>You can access all posts with a for each loop and pass them to the partials with the <code>{{&gt; postCard}}</code> template. The <code>@custom.adsense_enable</code> is a custom config written in the <code>package.json</code> file and used in the theme to check that the website owner has enabled AdSense on-site or not. The custom config enables you to go to Ghost &gt; Settings &gt; Design &gt; and to click on Site-wide and enable Adsense.</p>
<h3 id="heading-how-to-create-a-posts-page">How to Create a Posts Page</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/post.png" alt="Create post.hbs in the ghost theme" width="600" height="400" loading="lazy">
<em>Create <code>post.hbs</code> in the Ghost theme</em></p>
<p>The posts page is where readers will read your articles on your site. You can create a posts page with the following code.</p>
<pre><code class="lang-handlebars">{{!&lt; default}}

{{#post}}


{{!-- Pass reading_time time to authors partials with block , learn more about about block https://ghost.org/docs/themes/helpers/block/ --}}
{{#contentFor "fastestReadingTime"}}

 &lt;p class="text-slate-600 dark:text-slate-400 text-xs xs:text-xs sm:text-xs md:text-sm lg:text-sm xl:text-sm 2xl:text-sm "&gt;
    {{reading_time}}
 &lt;/p&gt;

{{/contentFor}}

{{#match @custom.adsense_enable "Enable"}}

    {{&gt; ads}}

{{/match}}

&lt;article class="{{post_class}} w-6/6 p-2"&gt;

    &lt;!-- Heading section --&gt;

    &lt;div class="m-auto mb-4 w-6/6 xs:w-5/6 sm:w-5/6 md:w-5/6 lg:w-5/6 xl:w-5/6 2xl:w-5/6"&gt;
        &lt;h1 class="mt-8 text-3xl xs:text-4xl sm:text-5xl md:text-5xl xl:text-5xl 2xl:text-5xl"&gt;
             {{title}} 
        &lt;/h1&gt;
        &lt;p class="text-slate-600 dark:text-slate-500 mt-2 text-1xl"&gt;
            {{excerpt}}
        &lt;/p&gt;
    &lt;/div&gt;

    &lt;!--  Author card partials/authors --&gt;
    {{&gt; authors}}



    &lt;!-- article thumbnail with partials/authors --&gt;
    {{&gt; featureImage}}


    &lt;!-- article body --&gt;
    &lt;div class="prose-lg prose-neutral m-auto p-2 my-10 w-10/12"&gt;
        {{content}}
    &lt;/div&gt;




&lt;/article&gt;


    {{!-- partials/comment --}}
    {{&gt; comment}}


{{!-- Add adsense  --}}
{{#match @custom.adsense_enable "Enable"}}

    {{&gt; ads}}

{{/match}}

{{!-- Show related posts --}}
{{#get "posts" filter="authors:{{primary_author.slug}}+id:-{{id}}" limit="3" include="authors"}}

{{!-- if post is available then show it --}}
{{#if posts}}

&lt;h2 class="mt-10 m-auto text-left w-5/6 text-xl xs:text-1xl sm:text-3xl md:text-4xl xl:text-5xl 2xl:text-6xl"&gt;
    Read more
&lt;/h2&gt;

{{!-- loop all post --}}
{{#foreach posts}}
    {{&gt; postCard }}
{{/foreach}}

{{/if}}

{{/get}}

{{!-- Add adsense  --}}
{{#match @custom.adsense_enable "Enable"}}

    {{&gt; ads}}

{{/match}}

{{/post}}

{{!-- newsletter partials --}}
{{&gt; newsletter}}
</code></pre>
<p>The fastestReadingTime block is to pass the reading time to the author partials. The <code>@custom.adsense_enable</code> is a custom config written in the <code>package.json</code> file and used in the theme to check that the website owner has enabled AdSense on-site or not. The custom config enables you to go to Ghost &gt; Settings &gt; Design &gt; and to click to Site-wide and enable Adsense.</p>
<h3 id="heading-how-to-create-informational-pages">How to Create Informational Pages</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/page.png" alt="Create page.hbs in the ghost theme" width="600" height="400" loading="lazy">
<em>Create <code>page.hbs</code> in the ghost theme</em></p>
<p>The <code>page.hbs</code> file helps you create informational pages for your website. For example, you can create an about, contact, privacy policy, or disclaimer page on your site. </p>
<pre><code class="lang-handlebars">{{!&lt; default}} 

{{#post}} 

    {{!--Pass reading_time time to authors partials with block , learn more about about block https://ghost.org/docs/themes/helpers/block/     --}}
    {{#contentFor "fastestReadingTime"}}

    &lt;p class="text-grey-600 text-xs xs:text-xs sm:text-xs md:text-sm lg:text-sm xl:text-sm 2xl:text-sm "&gt;
        {{reading_time}}
    &lt;/p&gt;
    {{/contentFor}}

{{!-- Add adsense base of if enable on theme  --}}
    {{#match @custom.adsense_enable "Disable"}}

        {{&gt; ads}}

    {{/match}}

    &lt;article class="{{post_class}}  w-6/6 p-2"&gt;

        &lt;!-- Heading section --&gt;
        &lt;div class=" m-auto mb-16 w-6/6 xs:w-5/6 sm:w-5/6 md:w-5/6 lg:w-5/6 xl:w-5/6 2xl:w-5/6"&gt;
            &lt;h1 class="text-gray-800 mt-8 text-3xl xs:text-4xl sm:text-4xl md:text-5xl xl:text-6xl 2xl:text-8xl"&gt;
                {{title}}
            &lt;/h1&gt;
            &lt;p class="text-gray-600 text-xl xs:text-xl sm:text-xl md:text-1xl xl:text-2xl 2xl:text-2xl"&gt;
                {{excerpt}}
            &lt;/p&gt;
        &lt;/div&gt;

        &lt;!--  partials/authors --&gt;
        {{&gt; authors}}


        {{!--  partials/featureImage  --}}
        {{&gt; featureImage}}



        &lt;!-- article body --&gt;
        &lt;div class=" prose-xl prose-neutral m-auto p-2 my-10 w-10/12"&gt;
            {{content}}
        &lt;/div&gt;



    &lt;/article&gt;


    {{!-- Add adsense  --}}
    {{#match @custom.adsense_enable "Disable"}}

        {{&gt; ads}}

    {{/match}}

    {{/post}}
</code></pre>
<p>The fastestReadingTime block is to pass the reading time to the author partials. The <code>@custom.adsense_enable</code> is a custom config written in the <code>package.json</code> file and used in the theme to check that the website owner has enabled AdSense on-site or not. The custom config enables you to go to Ghost &gt; Settings &gt; Design &gt; and to click to Site-wide and enable Adsense.</p>
<h3 id="heading-how-to-create-an-author-page">How to Create an Author Page</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/author.png" alt="Create author.hbs in the ghost theme" width="600" height="400" loading="lazy">
<em>Create <code>author.hbs</code> in the ghost theme</em></p>
<p>Author pages let you describe the author. You can show the author's name, bio, and related articles.</p>
<pre><code class="lang-handlebar">{{!&lt; default}}

{{#author}}

{{!--  Author Section pass with block learn more about about block https://ghost.org/docs/themes/helpers/block/ --}}
   {{#contentFor "authorName"}}
      {{name}}
    {{/contentFor}}

&lt;div class="container mt-20 mb-16 flex flex-col justify-between mx-auto"&gt;

    &lt;div class="flex flex-col mt-6 w-6/6 xs:w-5/6 sm:w-5/6  md:w-3/6 lg:w-3/6 xl:w-3/6 2xl:w-3/6 xs:mt-6 sm:mt-6 md:mt-6 lg:mt-0 xl:mt-0 2xl:mt-0 "&gt;

        &lt;h1 class="text-3xl mt-5 xs:text-3xl sm:text-3xl md:text-4xl xl:text-5xl 2xl:text-6xl"&gt; {{name}} &lt;/h1&gt;

        {{#if bio}}
            &lt;p class="mt-0 xs:mt-0 sm:mt-0 md:mt-1 lg:mt-3 xl:mt-3 2xl:mt-3 text-md"&gt;
                {{bio}}
            &lt;/p&gt;
        {{/if}}

        &lt;ul class="flex flex-row my-3"&gt;

            &lt;li class="text-md"&gt;{{location}}&lt;/li&gt;

               {{#if facebook}}

                    &lt;li class="mx-3 text-sm flex items-center"&gt;
                        &lt;a target="_blank" href="https://facebook.com/{{facebook}}" &gt;

                        {{!-- Pass partials/Icons/facebook --}}
                            {{&gt; Icons/facebook}}

                        &lt;/a&gt;
                    &lt;/li&gt;

                {{/if}}
                {{#if twitter}} 
                    &lt;li class="mx-3 text-sm flex items-center"&gt;
                        &lt;a target="_blank" href="https://twitter.com/{{twitter}}" &gt;

                        {{!-- Pass partials/Icons/twitter --}}
                            {{&gt; Icons/twitter}}

                        &lt;/a&gt;
                    &lt;/li&gt;
                {{/if}}
                {{#if website}} 
                    &lt;li class="mx-3 text-sm flex items-center"&gt;
                        &lt;a target="_blank" href="{{website}}" &gt;

                            {{!-- Pass partials/Icons/website --}}
                            {{&gt; Icons/website}}

                        &lt;/a&gt;
                    &lt;/li&gt;
                {{/if}}
        &lt;/ul&gt;
    &lt;/div&gt;
&lt;/div&gt;


{{!--  get posts related to author base on author Id --}}
    {{#get "posts" limit="all" filter="authors:{{slug}}+id:-{{id}}" order="published_at desc"   }}

        {{#if posts}}
                {{#foreach posts}}
                    {{&gt; authorCard}}
                {{/foreach}}
        {{/if}}

    {{/get}}

{{/author}}
</code></pre>
<h3 id="heading-how-to-create-a-tags-page">How to Create a Tags Page</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/tag.png" alt="Create tag.hbs in the ghost theme " width="600" height="400" loading="lazy">
<em>Create tag.hbs in the ghost theme</em></p>
<p>You can use the <code>tag.hbs</code> file to show articles related to the tag used.</p>
<pre><code>{{!&lt; <span class="hljs-keyword">default</span>}}


{{#tag}}

&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"container m-auto mt-32  mb-16  w-5/6 xs:w-5/6 sm:w-5/6 md:w-5/6 lg:w-5/6 xl:w-5/6 2xl:w-5/6"</span>&gt;

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">" text-gray-800 text-4xl xs:text-5xl sm:text-6xl md:text-7xl xl:text-8xl 2xl:text-9xl"</span>&gt;</span>{{name}}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>

    {{#<span class="hljs-keyword">if</span> description}}
        &lt;p <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">" text-gray-600 text-xl xs:text-xl sm:text-xl md:text-1xl xl:text-2xl 2xl:text-2xl"</span>&gt;
            {{description}}       
        &lt;/p&gt;
    {{/<span class="hljs-keyword">if</span>}}


&lt;/div&gt;

{{!--  get posts related to tag base on  tag slug --}}

    {{#get <span class="hljs-string">"posts"</span> include=<span class="hljs-string">"authors,tags"</span> limit=<span class="hljs-string">"3"</span> filter=<span class="hljs-string">"tag:{{slug}}"</span> <span class="hljs-keyword">as</span> |related|}}

   {{!-- loop posts base on article --}}
        {{#foreach related}}

    {{!--  check condition define <span class="hljs-keyword">in</span> config section <span class="hljs-keyword">in</span> package.json and add adsense code after every third post --}}
            {{#has number=<span class="hljs-string">"nth:3"</span>  }}
                {{#match @custom.adsense_enable <span class="hljs-string">"Enable"</span>}}
                    {{&gt; ads}}
                {{/match}}
            {{/has}}

        {{!-- partials/postCard.hbs --}}
            {{&gt; postCard }}

        {{/foreach}}

    {{/get}}

{{/tag}}
</code></pre><h3 id="heading-how-to-create-an-error-page">How to Create an Error Page</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/404error-1.png" alt="Create error.hbs in the ghost theme" width="600" height="400" loading="lazy">
<em>Create <code>error.hbs</code> in the ghost theme</em></p>
<p>You use the <code>error.hbs</code> file to show when any errors occur on the website. Error pages help your website not break in production. The most common error is a 404 (not found) error.</p>
<pre><code>{{!&lt; <span class="hljs-keyword">default</span>}} 
&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"flex flex-col m-auto p-10 w-5/6 xs:w-5/6 sm:w-5/6 md:w-5/6 lg:w-5/6 xl:w-5/6 2xl:w-5/6"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 10.8rem;"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-black text-center"</span>&gt;</span>
        {{statusCode}}
    <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-4xl -m-6 text-center"</span>&gt;</span>
        {{message}}
    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center w-32 m-auto my-20 p-3 bg-black text-white items-center rounded-full"</span>&gt;</span>
        Home
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><h3 id="heading-how-to-enable-comments">How to Enable Comments</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/comment-1.png" alt="enable comment in the ghost theme" width="600" height="400" loading="lazy">
<em>enable comments in the ghost theme</em></p>
<p>Ghost 5 officially supports <a target="_blank" href="https://ghost.org/docs/themes/helpers/comments/">the commenting system</a> (it's built-in) and you can just enable comments on the theme by copying and pasting the code – you never need any configuration. Ghost itself handles all the configurations. Here's the code:</p>
<pre><code class="lang-handlebars">&lt;div class="m-auto my-8 w-10/12"&gt;
    &lt;p class="text-right text-xs xs:text-xs sm:text-xs md:text-sm lg:text-sm xl:text-sm 2xl:text-sm "&gt;
        Before comment read our &lt;a style='text-decoration: underline' href="https://officialrajdeepsingh.dev/terms-and-conditions/"&gt;term and condition &lt;/a&gt;
    &lt;/p&gt;
    &lt;div class="mt-5 mb-5 p-4"&gt;

   {{!--  Enable comment on theme --}}
       {{comments}}
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h3 id="heading-how-to-set-up-search">How to Set Up Search</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/12/serach-bar.png" alt="enable the search bar in the ghost theme" width="600" height="400" loading="lazy">
<em>enable the search bar in the ghost theme</em></p>
<p>Ghost 5 comes with the <a target="_blank" href="https://ghost.org/docs/themes/helpers/search/">official support of search functionality</a>. You do not need any other configuration. Just paste the following code into your theme and the search functionally will start working on your site. </p>
<pre><code class="lang-handlebars">{{!-- partials/Icons/search --}}
&lt;button class="gh-search" data-ghost-search&gt;{{&gt; Icons/search}}&lt;/button&gt;
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a theme with Ghost is a relatively straightforward process compared to WordPress. The Ghost team has created well-defined documentation that you can easily follow as a beginner with examples. </p>
<p>They also provide many ready-made components, like search functionality, amp page, comments, and so on.</p>
<p>You can create your Ghost theme by copy-pasting the code. For beginner developers, it might seem a bit complicated, but you'll get the hang of it with some time and work. </p>
<p>The Ghost team has created a well-defined folder structure for theme development. It is the easiest way to manage the theme development process. You can also use npm packages to enhance the development process and add more functionality to the theme. In my theme, I use tailwind CSS and the Gulp package to speed up the development process.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose a CMS – WordPress vs Ghost vs Shopify ]]>
                </title>
                <description>
                    <![CDATA[ WordPress, Shopify, and Ghost are some of the most powerful and popular CMS platforms out there. And you might wonder why so many people use them. Well, it's because they're easy to use, cost-effective, and highly efficient. With WordPress, Shopify, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/chose-a-cms-wordpress-vs-shopify-vs-ghost/</link>
                <guid isPermaLink="false">66d45e3f3a8352b6c5a2aa32</guid>
                
                    <category>
                        <![CDATA[ blog ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ecommerce ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ghost ]]>
                    </category>
                
                    <category>
                        <![CDATA[ shopify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Edan Ben-Atar ]]>
                </dc:creator>
                <pubDate>Wed, 02 Feb 2022 17:05:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/WordPress-vs-Ghost-vs-Shopify.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>WordPress, Shopify, and Ghost are some of the most powerful and popular CMS platforms out there.</p>
<p>And you might wonder why so many people use them. Well, it's because they're easy to use, cost-effective, and highly efficient.</p>
<p>With WordPress, Shopify, and Ghost, you can create a website from scratch in a matter of minutes.</p>
<p>Tailored to your needs, these <a target="_blank" href="https://www.weblime.com/stories/top-website-builders">powerful website builders</a> can help you achieve anything from building an e-commerce website to starting your own blog or showcasing your portfolio.</p>
<p>It's no wonder why so many businesses choose these platforms. But which one should you choose?</p>
<p>We can't simply say that one is better than the other, because there's no single solution that will work in every situation.</p>
<p>So in this article, we'll cover the three platforms and look at their strengths and weaknesses so that you can figure out what will work best for your particular situation.</p>
<h2 id="heading-if-you-want-to-build-a-blog-from-scratch-use-ghost">If you Want to Build a Blog From Scratch – Use Ghost</h2>
<p>If you are a blogger who is looking for an open-source platform, <a target="_blank" href="https://ghost.org/">Ghost</a> might be the perfect choice for you.</p>
<p>The fact that it’s open-source enables you to alter the code of the platform, customize it, and make it more suitable to your writing needs.</p>
<p>And even if you’re not a coder, you can get help from other users who are willing to contribute to the community by fixing bugs or adding new features.</p>
<p>Tutorials on how to install Ghost on your own web server are available online. You can also choose to go with a hosted plan, which allows you to use themes created by other users instead of relying on the default theme.</p>
<p>Ghost is a platform that is based on Node.js, and it runs using Node.js servers. It comes with a rich plugin system, allowing you to customize your blog to suit your own needs.</p>
<p>Ghost lets you to use Markdown instead of HTML for writing. This makes it easy for you to write directly in the browser window.</p>
<p>If you don’t know about Markdown, it is a lightweight markup language that allows you to write in rich text but with simpler code, as opposed to HTML.</p>
<p>In fact, one of the benefits of Ghost over other platforms is that your posts are written in Markdown rather than HTML or text files, which results in much cleaner code.</p>
<h3 id="heading-you-can-use-ghost-as-a-headless-cms">You Can Use Ghost as a Headless CMS</h3>
<p>Ghost has a flexible architecture, which means it can be used as a headless CMS. In fact, it's one of the most popular headless content management systems in the JAMStack.</p>
<p>A <a target="_blank" href="https://www.freecodecamp.org/news/what-is-headless-cms-explained/">headless CMS</a> allows you to build a front-end website or application, such as a mobile app, with an API that calls the CMS for its data. You can deploy the API and your website or app to separate servers or environments without having to change anything within your content.</p>
<p>Since the API delivers data from the CMS, you will have full control over that data, including permissions, tags, and categories. If you need to make changes to your content, you will only have to make those changes on one end rather than both.</p>
<p>Headless CMSs are often used for building websites and applications with JavaScript frameworks such as AngularJS and React.js​. However, if you need to render a dynamic site with multiple pages using a single API call, this type of CMS can be beneficial as well.</p>
<p>To use a headless CMS, you will need to learn how it works and how to utilize it through its API. This may require additional development resources, depending on your skill level.</p>
<p>This approach is gaining popularity among startups and agencies who want more control over the display of content while still retaining the ability to make updates through a central interface.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/ghost-screenshot-admin.png" alt="Screenshot of Ghost admin interface" width="600" height="400" loading="lazy"></p>
<h3 id="heading-advantages-of-using-ghost">Advantages of Using Ghost</h3>
<p>Ghost is a free, easy-to-use CMS that doesn’t require any kind of coding skills.</p>
<p>Along with simplicity, Ghost CMS comes with lots of out-of-the-box features which make it really appealing to bloggers and small businesses.</p>
<p>You can add multiple authors, set up collaborative writing, track analytics, create polls, customer support forums, manage templates, and much more using drag and drop features.</p>
<p>Things get interesting as you start using third-party apps on Ghost. There are numerous integrations available for installing apps like Google Analytics and Disqus comments.</p>
<p>Some other pros include:</p>
<ul>
<li><p><strong>It has a clean, minimalistic design</strong>. If you want your blog to be beautiful, then Ghost CMS is great for that.</p>
</li>
<li><p><strong>Complete tools</strong>. You get all the tools that are required in creating a blog, starting from the installation to setting up the theme with the drag and drop features.</p>
</li>
<li><p><strong>Customizable themes</strong>. The themes can be customized using the built-in theme editor that makes it really easy for anyone to modify them as per their needs.</p>
</li>
<li><p><strong>Ghost community</strong>. If you’re stuck, you can find help from other Ghost users by going over their forums and asking questions.</p>
</li>
</ul>
<h2 id="heading-if-you-want-to-take-your-website-to-the-next-level-use-wordpress">If You Want to Take Your Website to the Next Level – Use WordPress</h2>
<p>You can use <a target="_blank" href="https://wordpress.org/">WordPress</a> as a simple blogging platform, but it is also a fully-featured content management system (CMS). It allows you to build custom websites and blogs if you want to take your business to the next level.</p>
<p>Because of its popularity, there is an active support community and lots of free training materials.</p>
<p>Tutorials for the basic functionality and more advanced features are widely available online.</p>
<p>WordPress is free, but if you need help installing it or customizing it for your needs, you can purchase web hosting from a reputable company. Hosting costs vary depending on the type of hosting service you choose.</p>
<p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-get-started-with-wordpress/">You can install WordPress yourself</a> or pay someone to do it for you. The WordPress website provides instructions on how to install the software on different server platforms.</p>
<p>Once installed on your server, WordPress will allow you to create your own blog page. You have complete control over the look and feel of your site through the use of themes, which are pre-built designs for the layout of your pages.</p>
<p>Themes are available for purchase or free download from the WordPress website. You can also <a target="_blank" href="https://www.freecodecamp.org/news/learn-how-to-create-your-own-wordpress-theme-from-scratch/">design your own custom theme</a> if you're up to the challenge.</p>
<p>You might want a more complicated site than what is provided by the basic WordPress installation. In that case, you can hire a designer to build you a customized theme or using an existing theme as a framework and add your own custom features through plugins. Plugins extend the features of themes with special design elements and programming functions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/WordPress-screen-themes.png" alt="Screenshot of WordPress themes in the admin UI" width="600" height="400" loading="lazy"></p>
<h3 id="heading-advantages-of-using-wordpress">Advantages of using WordPress</h3>
<p>WordPress is by far the most customizable option in this list. It features the most comprehensive library of themes and plugins, allows you to edit the source code quite easily, and even write your own custom functionalities.</p>
<p>You can think of WordPress as the CMS that falls between Ghost and Shopify, as it allows you to run an eCommerce store and a blog at the same time by simply installing a compatible theme.</p>
<p>WordPress lets you take your blog to the next level and scale your eCommerce store as your business grows.</p>
<p>The downside is that sooner or later you will need a developer’s help. This is because the more plugins you install, the slower your website will get, and users hate slow websites (not to mention search engines).</p>
<p>Some other pros include:</p>
<ul>
<li><p><strong>Extremely cheap to get started with</strong>. You can get a WordPress website up and running for free, and basic hosting plans start as low as $18.96 per year.</p>
</li>
<li><p><strong>Ability to assign user roles</strong>. At some point during your business growth cycle, you might need to bring in extra people to help you create, edit and publish content. WordPress comes with built-in user roles which will make your life a whole lot easier.</p>
</li>
<li><p><strong>Best marketing plugins on the market</strong>. You can install one of the many SEO plugins available in the plugin directory. Some examples include Yoast or Rank Math. These plugins help you optimize your content (like articles, pages, and even product pages) and increase your chances of outranking your competitors.</p>
</li>
<li><p><strong>A vast array of integrations</strong>. Chances are you will be using 3rd party SaaS products like Mailchimp or ActiveCampaign. Regardless of the service, you will find it extremely easy to integrate them with your website as almost all have created a WordPress plugin.</p>
</li>
<li><p><strong>The biggest online library of resources</strong>. The WordPress community is by far the largest which makes it easy to find answers to all your questions regarding your installation. There are tens of thousands of websites and forums focused solely on WordPress websites featuring tons of information.</p>
</li>
</ul>
<h2 id="heading-if-you-want-the-fastest-way-to-start-an-ecommerce-business-use-shopify">If You Want the Fastest Way to Start an eCommerce Business – Use Shopify</h2>
<p><a target="_blank" href="https://www.shopify.com/">Shopify</a> started in 2006 as an online store for snowboarding equipment. Back then, the CMS ecosystem was lacking a robust and easy-to-use solution, so the Shopify creators decided to code their own.</p>
<p>Needless to say, this was a hit. In the years that followed more and more stores have started to use the Shopify CMS. As of May 2021, more than 1.7 million businesses from some 175 countries use Shopify to run their businesses.</p>
<p>By far the simplest and fastest way to start an eCommerce business, Shopify is mainly used by nontechnical people that want to bring their brick and mortar stores online. In no more than a few minutes you can have your own website up and running and start accepting online payments.</p>
<p>But Shopify is also used by some of the biggest online stores on the Internet, which makes it a great option if you want to scale your business to the next level, and have the funds to do so.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/Shopify-screenshot.png" alt="Screenshot of Shopify UI" width="600" height="400" loading="lazy"></p>
<p>Some of Shopify’s advantages:</p>
<ul>
<li><p><strong>Extremely easy to get started with</strong>. The CMS was built with ease of use in mind. Anyone can get a store up and running in no time. You don’t have to know how to code or even how to connect a domain to your website as Shopify does all that for you.</p>
</li>
<li><p><strong>Compatible with most major third-party services</strong>. Shopify connects out of the box with the biggest third-party services, like Klaviyo for email marketing or Facebook Ads for paid advertising.</p>
</li>
<li><p><strong>Plenty of apps in the app store</strong>. If you feel that your store needs additional functionality, like bundle discounts, for example, you will be happy to hear that there are tons of apps that can help you achieve this. Just be careful and look at their cost as they can go up rather quickly.</p>
</li>
</ul>
<p>Some of Shopify’s disadvantages:</p>
<ul>
<li><p><strong>Can get pretty expensive</strong>. Shopify is extremely easy to start with, but that comes with a cost. The cheapest plan (Basic) starts at $29 per month, while the most expensive one (Advanced) reaches $299 per month. The main difference is the commission applied by Shopify on payments.</p>
</li>
<li><p><strong>High payment fees</strong>. You have to take into account that Shopify charges up to a 2% fee on your transactions (on the Basic plan). This commission decreases with the plan to a minimum of 0.5% (on the Advance plan). In comparison, WooCommerce doesn’t charge you a percentage of your sales.</p>
</li>
<li><p><strong>Shopify developers are expensive</strong>. If you want to customize your store beyond basic functionalities you will need the help of a developer, and they are not cheap. However, there are a multitude of apps available that can help you achieve your goals.</p>
</li>
<li><p><strong>Most Shopify Apps have a monthly cost</strong>. You can find free apps in the app store, but most of them have a monthly cost (compared to a fixed one-time fee charged by the vast majority of WordPress plugins).</p>
</li>
<li><p><strong>The blog functionality isn't great</strong>. Shopify is an eCommerce-centric platform so there’s no wonder that they haven’t spent too much time optimizing their blog functionality. Big stores choose to host their blogs on WordPress while keeping their storefront on Shopify.</p>
</li>
</ul>
<p>In conclusion, you can use Ghost to start your blog almost instantly, or Shopify to configure a fast and secure online store. And, if you want to get the best out of both worlds, you might want to go with WordPress.</p>
<p><a target="_blank" href="https://www.weblime.com/stories/the-ultimate-wordpress-guide">The ultimate WordPress guide</a> is a free resource that will help you understand the basics and help you launch your new website in no time, so be sure to give it a read before you make the big decision of choosing a specific platform.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ WordPress Installation Guide – How to Get Started with WordPress + the Best Plugins ]]>
                </title>
                <description>
                    <![CDATA[ Over 40% of all websites on the internet are powered by WordPress, making it the world’s top choice when it comes to creating a website. Many people and businesses choose to create their websites with WordPress because of its versatility, speed, and ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-started-with-wordpress/</link>
                <guid isPermaLink="false">66d45e40246e57ac83a2c731</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Edan Ben-Atar ]]>
                </dc:creator>
                <pubDate>Wed, 08 Sep 2021 18:00:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/How-to-Get-Started-with-WordPress.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><a target="_blank" href="https://w3techs.com/technologies/details/cm-wordpress">Over 40%</a> of all websites on the internet are powered by WordPress, making it the world’s top choice when it comes to creating a website.</p>
<p>Many people and businesses choose to create their websites with WordPress because of its versatility, speed, and ease of use.</p>
<p>WordPress is also Open Source, which means that anyone can use and edit the code for free, forever. All you need to get started is a domain and hosting provider, which brings the cost of creating a website lower than a coffee and bagel combo.</p>
<p>WordPress runs on PHP and MySQL, but you don’t need to be a developer to get started. Because it’s Open Source, a large number of organizations have built plugins on top of the basic platform which makes it easy for anyone to design a website, create a forum, or even set up an online store, all without writing a single line of code.</p>
<p>Most plugins are free to use when you get started, with the costs increasing based on usage or the extra features you need. Later in the article, I will share 3 of the most popular WordPress plugins that will help you create a website just the way you want.</p>
<h2 id="heading-popular-websites-created-on-top-of-wordpress">Popular Websites Created On Top of WordPress</h2>
<p>You might be thinking that WordPress is used only by individuals and small businesses, but this is far from the truth.</p>
<p>Some of the biggest news publications in the world chosen this CMS and blogging platform as the base for their websites. Websites like <a target="_blank" href="https://techcrunch.com/">TechCrunch</a>, <a target="_blank" href="https://www.bbcamerica.com/">BBC America</a>, and <a target="_blank" href="https://www.nytco.com/">The New York Times</a> all use WordPress as their content management system.</p>
<p>Even the <a target="_blank" href="https://www.whitehouse.gov/">White House’s website</a> is built on top of WordPress.</p>
<p>I do want to point out that the previously presented websites are using the version of the CMS as presented on wordpress.org and not the wordpress.com one.</p>
<h3 id="heading-what-is-the-difference-between-wordpressorg-and-wordpresscom">What is the difference between wordpress.org and wordpress.com?</h3>
<p>Wordpress.org allows you to download the WordPress source code so you can install it on your own server. Wordpress.com, on the other hand, allows you to instantly create a website that is hosted on their platform.</p>
<h2 id="heading-how-to-get-started-with-wordpress">How to Get Started with WordPress</h2>
<p>I am going to cover 3 different ways to get your website up and running using WordPress.</p>
<p>The cheapest way is to grab a shared hosting plan and setup your website yourself. This requires a bit of technical knowledge or Google search skills.</p>
<p>The easiest but a bit more expensive way to get started is to go for a dedicated WordPress hosting plan. In this case, all you will need to do is buy a domain and link it to the website.</p>
<p>The third way to get started is to simply go with a wordpress.com hosted website. This is by far the most expensive option on this list.</p>
<h3 id="heading-the-cheapest-way-to-get-started-with-wordpress">The cheapest way to get started with WordPress</h3>
<p>This option starts at $2.32 per month and requires you to use cPanel and install the source code yourself. Even though it sounds complicated and technical, you just need to navigate something called cPanel and click a few buttons.</p>
<p>If you go this route you will need to buy hosting and a domain (otherwise your URL will look something like this https://100.100.8.8).</p>
<p>In recent years, the price of both hosting and domains has plummeted. Take <a target="_blank" href="https://www.namecheap.com/">Namecheap</a> for example – they sell .com domains that start at $8.99 per year and can also host your website for $18.96 per year.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/shared-hosting-plans.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This brings the cost of running a website to $27.95 for your first year or <strong>just $2.32 per month.</strong></p>
<h3 id="heading-the-easiest-way-to-host-your-own-wordpress-website">The easiest way to host your own WordPress website</h3>
<p>This option costs just a few cents more than the previous option (starts at $2.65 per month), but it’s by far the easiest way to host your own website. It’s important to mention that the price also covers the domain, not only the hosting.</p>
<p>This example takes into account the <a target="_blank" href="https://www.namecheap.com/wordpress/pricing/">EasyWP Managed WordPress Hosting</a> cheapest plan.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/easywp-managed-wordpress-hosting.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>All you have to do is sign up for an account, complete the 5 step process, and your website is live. That’s it.</p>
<p>The Starter plan limits your website to 50,000 visitors per month and gives you 10 GB of storage space (for images, videos, and so on). This is enough to get you started, and remember – you can always upgrade it if your website starts to get traction.</p>
<h3 id="heading-the-fastest-way-to-start-a-website-without-worrying-about-hosting">The fastest way to start a website without worrying about hosting</h3>
<p>If you don’t want to worry about hosting at all, this option is for you. I don’t recommend going this route as your costs will start rising rapidly, especially if you want to get the most out of the WordPress functionality.</p>
<p>For example, you will be forced to pay $25 per month just to be able to install a plugin. That’s close to 7 times more expensive than the previous option, and it doesn’t even cover the domain!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/wordpress-com-hosting.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you still want to use wordpress.com, all you have to do is to sign up for an account (either create an account with your email or use your Google or Apple accounts), pick a domain (they offer a free one as well), and you are all set.</p>
<h2 id="heading-wordpress-dashboard">WordPress Dashboard</h2>
<p>Regardless of how you create your new WordPress website, once you log in you will see the same dashboard. Something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/wordpress-dashboard.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The website in the above screenshot has a few plugins installed, like Elementor, Autoptimize, and Yoast SEO, which I will cover in the next section.</p>
<h2 id="heading-wordpress-plugins-to-install-on-your-site">WordPress Plugins to Install on Your Site</h2>
<p>WordPress powers more than 40% of all websites because of its versatility. The base functionality is great, but the ability to install plugins takes it to the next level.</p>
<p>You can install:</p>
<ul>
<li><p>Website builder plugins (Elementor, WP Bakery, Beaver Builder, and more)</p>
</li>
<li><p>Ecommerce plugins (WooCommerce, Easy Digital Downloads, WP Easy Cart, and so on)</p>
</li>
<li><p>Speed optimization plugins (a3 Lazy Load, WP Rocket, W3 Total Cache, and so on)</p>
</li>
<li><p>SEO plugins (Yoast, Redirection, Rank Math, and more)</p>
</li>
</ul>
<p>There are over 54,000 free plugins you can install on your website, not to mention the paid ones.</p>
<p>With such a large selection, it might be a bit overwhelming for you to choose the ones that you really need. So I compiled this list of 3 of the most important plugins for the ultimate WordPress setup.</p>
<p>Bear in mind that each additional plugin you install will make your website slower, so don’t overdo it.</p>
<h3 id="heading-elementor-plugin-website-builder">Elementor Plugin – Website Builder</h3>
<p>WordPress comes with a built-in website builder called Gutenberg, but this can hardly help you get the website you like.</p>
<p>This is why Elementor is a must-have plugin for someone that wants an eye-catching website without writing a single line of code.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/elementor-website-builder.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In order to install Elementor (or any other plugin), you have to navigate to your WordPress dashboard and hover over the Plugins item. Then just click on the “Add New” option:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/install-elementor-plugin.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Type in “elementor” in the search box and install the first one. Wait for a bit and click on “Activate”. This way, you will tell WordPress that you want to start using Elementor as soon as possible.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/search-for-elementor.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>A new menu item will appear once you successfully install Elementor. To create your first page you will have to click on the “Templates” menu item (the one below “Elementor”) then just click “Add New”:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/add-new-elementor-template.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>With Elementor you can design anything from single pages to how your blog articles will look.</p>
<p>It’s one of the easiest drag-and-drop website builders plugins, plus they have a great resource library to get you started in no time.</p>
<h3 id="heading-autoptimize-plugin-speed-optimization">Autoptimize Plugin - Speed Optimization</h3>
<p>There are tens if not hundreds of speed optimization plugins in the marketplace, and installing all of them will not make your website faster (on the contrary, it will slow it down).</p>
<p>Moreover, depending on what option you have chosen to host your website, some plugins can completely destroy your website.</p>
<p>With that in mind, you should be extra cautious about what speed optimization plugins you decide to install. Make sure to always check with your hosting provider before installing any plugin.</p>
<p>However, one plugin that will work with absolutely any type of hosting and will surely boost your website’s speed is Autoptimize.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/autoptimize-plugin.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This plugin does it all in terms of speed:</p>
<ul>
<li><p>Minifies CSS and JS (makes the code of your website smaller)</p>
</li>
<li><p>Lazy loads images (they will get downloaded by the browser only when the user scrolls enough to see them)</p>
</li>
<li><p>Caches your CSS and JS (they will be loaded way faster by the browser)</p>
</li>
</ul>
<p>Autoptimize does all this automatically. You just have to install and activate it and that’s basically it.</p>
<p>When your website starts to grow you can use Autoptimize’s API to really take full advantage of all features, but if you are just starting out this plugin will make your website faster in a breeze.</p>
<h3 id="heading-yoast-plugin-seo-optimization">Yoast Plugin – SEO optimization</h3>
<p>Yoast is one of the most downloaded WordPress plugins. It helps you write better content that is easy to read by people and search engines alike.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/yoast-plugin.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Yoast can help your website rank higher on search engines by combining a suite of different functionalities:</p>
<ul>
<li><p>It can generate a sitemap for your website, making it easy for Google to understand your site structure</p>
</li>
<li><p>Automated technical SEO improvements, like canonical URLs and meta tags</p>
</li>
<li><p>An in-depth Schema.org integration that will increase your chance of getting rich results</p>
</li>
<li><p>Real-time readability and SEO analysis to help you write better blog posts and copy</p>
</li>
</ul>
<p>Yoast is very easy to set up. All you have to do is install and activate it and go through the onboarding process. Just add your website name, description, and type (blog, e-commerce, and so on) and Yoast will automatically start working for you.</p>
<p>Elementor, Autoptimize, and Yoast are 3 essential plugins for WordPress. Each one is packed with all the functionalities you will ever need to design, optimize and rank your website.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Whether you are a complete beginner or a pro at building websites, WordPress is undoubtedly one of the best choices when it comes to CMS platforms. It’s not only easy to set up but extremely cheap and versatile.</p>
<p>So go ahead and start building your new project, be it an online store, personal blog, or a resume website. With WordPress, you can do it all, in a single day.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Headless CMS Explained – What it is and When You Should Use it ]]>
                </title>
                <description>
                    <![CDATA[ By Daniel Madalitso Phiri CMSs are pretty hard to ignore because they're everywhere on the internet. WordPress, for example, powers nearly 40% of the internet today. In this article, we'll cover what CMSs are and why you should care about them. I'll ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-headless-cms-explained/</link>
                <guid isPermaLink="false">66d45e0073634435aafcef6a</guid>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ headless cms ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Madalitso Phiri ]]>
                </dc:creator>
                <pubDate>Tue, 27 Jul 2021 17:53:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/siora-photography-hgFY1mZY-Y0-unsplash-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Daniel Madalitso Phiri</p>
<p>CMSs are pretty hard to ignore because they're everywhere on the internet. WordPress, for example, powers nearly <a target="_blank" href="https://kinsta.com/wordpress-market-share/">40% of the internet</a> today.</p>
<p>In this article, we'll cover what CMSs are and why you should care about them. I'll also introduce you to a new type of CMS that seems to be everywhere at the moment – the Headless CMS. And we'll do all this with a story!</p>
<p>Life has a funny way of making you try things. And after years of ignoring CMSs as a technology, in mid 2020 I got a job at <a target="_blank" href="https://strapi.io">Strapi</a>, a headless CMS tool. Since then, I have developed a pretty good understanding of what these things do – so let's get into it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/ezgif.com-gif-maker-2-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-is-a-cms">What is a CMS?</h2>
<p>A Content Management System (CMS) is a tool that helps users create, manage, and modify digital content.</p>
<p>In this article, however, I won’t get into the nitty-gritty of it. Instead, if you want to learn more you can have a look at <a target="_blank" href="https://strapi.io/blog/frontend-developers-headless-cms">an article I wrote</a> that goes deeper into various types of CMSs.</p>
<h2 id="heading-what-is-a-headless-cms">What is a Headless CMS?</h2>
<p>A headless CMS has a back end where content is prepared – and that's it. The content and its data are only accessible via calls made to the API, whether it's REST or GraphQL.</p>
<p>I like to use this diagram to illustrate how Headless works, so hopefully it paints a clearer picture.</p>
<p><img src="https://lh3.googleusercontent.com/zPdxhP33Y_kqX1SY-KXDq0Ma1IiJv15urJ_PVuiogvtI86tCa_A2qMJ0L2UqFD_U_MmTy0VHED1Oz9w5uumNipKSBzwmHYkHRrgXrdrLU0PNg9nvhUQC28Hy09H9Wrn5iiBep95U" alt="Image" width="1600" height="802" loading="lazy"></p>
<p><em>Monolithic vs decoupled vs headless architectures</em></p>
<p>Besides serving content to multiple platforms, there are a couple other reasons why you would want to use a Headless CMS.</p>
<h3 id="heading-you-dont-want-to-give-up-developer-flexibility">You don’t want to give up developer flexibility</h3>
<p>Adopting a Headless architecture by default means that you have the flexibility of selecting a front end tool of your choosing. And for many developers, this is a critical advantage.</p>
<h3 id="heading-you-need-a-secure-content-solution">You need a secure content solution</h3>
<p>Decoupling the front end from the back end makes targeted attacks much harder. This is something some traditional CMSs still struggle with today.</p>
<h3 id="heading-you-want-to-future-proof-your-tech-stack">You want to future proof your tech stack</h3>
<p>Going headless also means that you’re less dependent on a single solution for a front end. Should you need to upgrade to a more modern front end or add a new front end altogether, headless makes this much easier.</p>
<h3 id="heading-you-need-to-create-custom-and-personalized-experiences">You need to create custom and personalized experiences</h3>
<p>This is becoming a really important benefit for headless CMSs for many organizations.</p>
<p>With headless you have the opportunity to tailor different experiences for different platforms all from a single content source.</p>
<h2 id="heading-how-i-got-into-headless-cmss">How I got into Headless CMSs</h2>
<p>So I really like GraphQL, and that’s how I got started with Strapi. Working for a CMS was like diving head first into this ecosystem. I thought I understood Headless CMSs because to me they were “data, API, frontend” and that’s how I thought about it.</p>
<p>Well, we use these things to build our front ends, but we often overlook the content management side of things when we think about building a front end like that. And it wasn't until I started working with Strapi that I recognized my assumption.</p>
<p>“Content Management” sounds kinda boring, right? And CMS? “Ewww why would I want to use such a tool?” I know! Me too, but hear me out. CMSs actually pretty useful. So let’s talk about how and why a CMS might help you out.</p>
<h2 id="heading-why-do-you-need-a-headless-cms">Why Do You Need a Headless CMS?</h2>
<p>For starters, there’s no downplaying the role of content in today's world. Content is everywhere and manifests itself in so many forms through text, audio, video, and more.</p>
<p>For a long time, computers and browsers were the main tool for content consumption. We read blogs, watched YouTube videos, and listened to podcasts on our personal computers.</p>
<p>Gradually our computers got smaller and less obvious. Content in its many shapes and forms started to appear all around us. It showed itself in mobile phones, on our smart televisions, in our cars, in our virtual assistants and wearable devices.</p>
<p>The way people consumed content changed, and so did the way we had to build content-consuming experiences.</p>
<h3 id="heading-so-how-does-headless-cms-help">So How Does Headless CMS Help?</h3>
<p>Traditionally, CMSs were monoliths with the front end and back end tightly coupled. The content you added in the CMS back end only showed up on the front end it was coupled to - think WordPress and Drupal.</p>
<p>This proved inefficient as developers needed a better way to build and adapt to this new consumer behavior.</p>
<p>The solution? Rip the head off a traditional CMS and make it possible for your back end to deliver content to multiple platforms. This was how Headless was born.</p>
<h2 id="heading-why-you-might-not-need-a-headless-cms">Why You Might Not Need a Headless CMS</h2>
<p>Headless isn't necessarily the right solution for all use cases, though. It might not be for you if...</p>
<h3 id="heading-you-have-a-small-team">You have a small team</h3>
<p>Adopting and building a headless architecture takes quite a bit of effort. To reap all its benefits you would have to have a dedicated developer team to build your front end as well as people on your team to work on adding content to your CMS.</p>
<h3 id="heading-you-rely-heavily-on-a-simple-live-preview-implementation">You rely heavily on a simple live preview implementation</h3>
<p>Live previews on Headless CMSs aren’t the most intuitive to set up (as of writing this) and take some effort from developers to implement.</p>
<h3 id="heading-you-only-require-simple-publishing-capabilities">You only require simple publishing capabilities</h3>
<p>As we just learned, headless takes a reasonable amount of effort to get it working efficiently and effectively.</p>
<p>If you need only simple publishing capabilities without features like internationalization or role-based access control, then it’s best to wait till you need those additional features to use a Headless CMS.</p>
<h2 id="heading-use-cases-for-a-headless-cms">Use Cases for a Headless CMS</h2>
<p>A lot of my early CMS projects centered around corporate sites and personal blogs, which are both solid use cases for headless. But I don’t build sites full time so I don’t ship code often.</p>
<p>Personally I’ve used a CMS to help build a <a target="_blank" href="https://foodadvisor.strapi.io/">Restaurant Catalog</a>, an <a target="_blank" href="https://conf.strapi.io/speakers">Event Website</a>, and an <a target="_blank" href="https://conf.strapi.io/quizz">Online Quiz</a>.</p>
<p>There’s folks using headless CMSs to build eCommerce sites, Covid tracking projects, hospital management systems, inventory management applications, mobile catalogs, VR games, and some people even run email campaigns with them. So many possibilities.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Seeing what people are building with CMSs is very inspiring. And I’ve gained a huge appreciation for CMSs as a technology. What I once thought was a boring tool actually powers so much of the world around me.</p>
<p>There are lots of use cases for Headless CMS these days. And while at the moment there is a huge focus on serving developers (which many CMSs are doing well), we still have a ways to go to make the content editor's experience better.</p>
<p>It’s exciting having a foot in the race, and all I can tell you is that it's going to be an amazing next few years for Headless technology in general.</p>
<p>So hopefully this article helps you jump on the bandwagon and get a better understanding of what the technology can and cannot do.</p>
<p>After all, at the end of the day, the choice is yours!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/javier-allegue-barros-C7B-ExXpOIE-unsplash.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><p><a target="_blank" href="https://jamstack.org/headless-cms/">Headless CMS</a> | Jamstack.org</p>
</li>
<li><p><a target="_blank" href="https://strapi.io/what-is-headless-cms">What is a Headless CMS</a></p>
</li>
<li><p><a target="_blank" href="https://www.stackbit.com/blog/what-is-a-headless-cms/">What’s a Headless CMS and Why Should You Care</a></p>
</li>
<li><p><a target="_blank" href="https://cms-comparison.io/#/card">CMS Comparison</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Blog with Gatsby and Netlify CMS – A Complete Guide ]]>
                </title>
                <description>
                    <![CDATA[ By Mohammed Asker In this article, we are going to build a blog with Gatsby and Netlify CMS. You will learn how to install Gatsby on your computer and use it to quickly develop a super fast blog site. You are also going to learn how to add Netlify CM... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-blog-with-gatsby-and-netlify-cms/</link>
                <guid isPermaLink="false">66d46040d14641365a050921</guid>
                
                    <category>
                        <![CDATA[ blog ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gatsby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 06 Oct 2020 15:16:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c984e740569d1a4ca1946.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mohammed Asker</p>
<p>In this article, we are going to build a blog with Gatsby and Netlify CMS. You will learn how to install Gatsby on your computer and use it to quickly develop a super fast blog site.</p>
<p>You are also going to learn how to add Netlify CMS to your site by creating and configuring files, then connecting the CMS to your site through user authentication. </p>
<p>And finally, you'll learn how to access the CMS admin so that you can write your first blog post.</p>
<p>The complete code for this project can be found <a target="_blank" href="https://github.com/mohammedasker/foodblog">here</a>.</p>
<p>Here's a brief introduction to these tools.</p>
<h2 id="heading-what-is-gatsby">What is Gatsby?</h2>
<p><a target="_blank" href="https://www.gatsbyjs.com/">Gatsby</a> is a free and open-source framework based on React that helps you build fast websites and web apps. It is also a static site generator like Next.js, Hugo, and Jekyll.</p>
<p>It includes SEO (Search Engine Optimization), accessibility, and performance optimization from the get-go. This means that it will take you less time to build production-ready web apps than if you were building with React alone.</p>
<h2 id="heading-what-is-netlify-cms">What is Netlify CMS?</h2>
<p><a target="_blank" href="https://www.netlifycms.org/">Netlify CMS</a> is a CMS (Content Management System) for static site generators. It is built by the same people who made <a target="_blank" href="https://www.netlify.com/">Netlify</a>. It allows you to create and edit content as if it was WordPress, but it's a much simpler and user-friendly interface.</p>
<p>The main benefit of Netlify CMS is you don't have to create markdown files every time you want to write a post. This is useful for content writers who don't want to deal with code, text editors, repositories, and anything to do with tech - they can just focus on writing articles.</p>
<p>Alright, without any further ado, let's start building the blog!</p>
<p><strong>But before we get going, a quick heads up</strong>: This guide requires prior knowledge of JavaScript and React. If you are not comfortable with these tools yet, I've linked the resources at the end of the article to help you brush up on those skills. </p>
<p>Even if you're new to those technologies, I tried to make this guide as simple as I was able so you can follow along.</p>
<h2 id="heading-how-to-set-up-the-environment">How to set up the environment</h2>
<p>Before we can build Gatsby sites, we have to make sure that we have installed all the right software required for the blog.</p>
<h3 id="heading-install-nodejs">Install Node.js</h3>
<p>Node.js is an environment that can run JavaScript code outside of a web browser.</p>
<p>It is a tool that allows you to write backend server code instead of using other programming languages such as Python, Java, or PHP. Gatsby is built with Node.js and that's why we need to install it on our computer.</p>
<p>To install Node.js, go to the <a target="_blank" href="https://nodejs.org/en/download/">download page</a> and download it based on your operating system. </p>
<p>When you are done following the installation prompts, open the terminal and run <code>node -v</code> to check if it was installed correctly. Currently, the version should be 12.18.4 and above.</p>
<h3 id="heading-install-git">Install Git</h3>
<p>Git is a free and open-source distributed version control system that helps you manage your coding projects efficiently. </p>
<p>Gatsby starter uses Git to download and install its required files and that's why you need to have Git on your computer.</p>
<p>To install Git, follow the instructions based on your operating system:</p>
<ul>
<li><a target="_blank" href="https://www.atlassian.com/git/tutorials/install-git#mac-os-x">Install Git on Mac OS</a></li>
<li><a target="_blank" href="https://www.atlassian.com/git/tutorials/install-git#windows">Install Git on Windows</a></li>
<li><a target="_blank" href="https://www.atlassian.com/git/tutorials/install-git#linux">Install Git on Linux</a></li>
</ul>
<h3 id="heading-install-gatsby-cli">Install Gatsby CLI</h3>
<p>Gatsby CLI (Command Line Interface) is the tool that lets you build Gatsby-powered sites. By running this command, we can install any Gatsby sites and the plugins we want.</p>
<p>To install Gatsby CLI, open the terminal and run this command:</p>
<pre><code>npm install -g gatsby-cli
</code></pre><p>Once everything is set up successfully then we are ready to build our first Gatsby site.</p>
<h2 id="heading-how-to-build-a-gatsby-site">How to build a Gatsby site</h2>
<p>In this guide, we're going to use the default Gatsby starter theme, but you're free to choose any themes on the <a target="_blank" href="https://www.gatsbyjs.com/starters/?v=2">Gatsby starter library</a>. I personally use the <a target="_blank" href="https://github.com/LekoArts/gatsby-starter-minimal-blog">Lekoart theme</a> because the design is minimalist and beautiful, and it has a dark mode.</p>
<p>In the terminal, run this command to install the new Gatsby blog:</p>
<pre><code>gatsby <span class="hljs-keyword">new</span> foodblog https:<span class="hljs-comment">//github.com/gatsbyjs/gatsby-starter-blog</span>
</code></pre><p><strong>Note for Windows users</strong>: If you encounter "Error: Command failed with exit code 1: yarnpkg" while creating Gatsby site, see <a target="_blank" href="https://github.com/gatsbyjs/gatsby/issues/26804">this page</a> to troubleshoot it. You may have to clean up dependencies of old yarn installations or follow the Gatsby on Windows instructions.</p>
<p>What's does this command line mean exactly? Let me explain.</p>
<ul>
<li><strong>new</strong> - This is the command line that creates a new Gatsby project</li>
<li><strong>foodblog</strong> - This is the name of the project. You can name it whatever you want here. I named this project <em>foodblog</em> as an example only.</li>
<li><strong>The URL</strong> (<a target="_blank" href="https://github.com/gatsbyjs/gatsby-starter-blog">https://github.com/gatsbyjs/gatsby-starter-blog</a>) - This URL specified points to a code repository that holds the starter code you want to use. In other words, I picked the theme for the project.</li>
</ul>
<p>Once the installation is complete, we'll run the <code>cd foodblog</code> command which will take us to the location of our project file.</p>
<pre><code>cd foodblog
</code></pre><p>Then we'll run <code>gatsby develop</code> that will start running on the local machine. Depending on the specs of your computer, it will take a little while before it is fully started.</p>
<pre><code>gatsby develop
</code></pre><p>Open a new tab in your browser and go to <code>http://localhost:8000/</code>. You should now see your new Gatsby site!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--33-.png" alt="Image" width="600" height="400" loading="lazy">
<em>How a Gatsby starter blog homepage looks</em></p>
<p>Now that we've created the blog, the next step is to add Netlify CMS to make writing blog posts easier.</p>
<h2 id="heading-how-to-add-netlify-cms-to-your-site">How to add Netlify CMS to your site</h2>
<p>Adding Netlify CMS to your Gatsby site involves 4 major steps:</p>
<ul>
<li>app file structure, </li>
<li>configuration, </li>
<li>authentication, and </li>
<li>accessing the CMS.</li>
</ul>
<p>Let's tackle each of these stages one at a time.</p>
<h3 id="heading-how-to-set-up-the-apps-file-structure">How to set up the app's file structure</h3>
<p>This section deals with the file structure of your project. We are going to create files that will contain all Netlify CMS codes.</p>
<p>When you open your text editor, you will see a lot of files. You can read <a target="_blank" href="https://github.com/gatsbyjs/gatsby-starter-blog#-whats-inside">this article</a> if you are curious about what each of these files does.</p>
<pre><code>├── node_modules
├── src
├── <span class="hljs-keyword">static</span>
├── .gitignore
├── .prettierrc
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── LICENSE
├── package-lock.json
├── package.json
└── README.md
</code></pre><p>Do not worry about all these files — we are going to use very few of them here. </p>
<p>What we are looking for is the <code>static</code> folder. This is the folder where it will form the main structure of the Netlify CMS. </p>
<p>If your project does not have <code>Static</code> folder, then create the folder at the root directory of your project.</p>
<p>Inside the <code>static</code> folder, create an <code>admin</code> folder. Inside this folder, create two files <code>index.html</code> and <code>config.yml</code>:</p>
<pre><code>admin
 ├ index.html
 └ config.yml
</code></pre><p>The first file, <code>index.html</code>, is the entry point to your CMS admin. This is where Netlify CMS lives. You don't need to do styling or anything as it is already done for you with the script tag in the example below:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Content Manager<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The second file, <code>config.yml</code>, is the main core of the Netlify CMS. It's going to be a bit complicated as we are going to write backend code. We'll talk more about it in the configuration section.</p>
<h3 id="heading-how-to-configure-the-back-end">How to configure the back end</h3>
<p>In this guide, we are using Netlify for hosting and authentication and so the backend configuration process should be relatively straightforward. Add all the code snippets in this section to your <code>admin/config.yml</code> file.</p>
<p>We'll begin by adding the following codes:</p>
<pre><code class="lang-yml"><span class="hljs-attr">backend:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">git-gateway</span>
  <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span>
</code></pre>
<p><strong>Heads up</strong>: This code above works for GitHub and GitLab repositories. If you're using Bitbucket to host your repository, follow these <a target="_blank" href="https://www.netlifycms.org/docs/bitbucket-backend/">instructions</a> instead.</p>
<p>The code we just wrote specifies your backend protocol and your publication branch (which is branch: master). Git Gateway is an open-source API that acts as a proxy between authenticated users of your site and your site repository. I'll explain more what this does in the authentication section.</p>
<p>Next up, we will write <code>media_folder: "images/uploads"</code>. This will allow you to add media files like photos directly to your CMS. Then you won't need to use a text editor to manually add media and all that.</p>
<pre><code class="lang-yml"><span class="hljs-attr">media_folder:</span> <span class="hljs-string">"images/uploads"</span>
</code></pre>
<p>Make sure you created a folder called <code>images</code> in the <code>admin</code> folder. Inside the <code>images</code> folder, create an <code>uploads</code> folder as this is the place where you'll host your images.</p>
<h3 id="heading-configure-collections">Configure Collections</h3>
<p>The collections will define the structure for the different content types on your static site. As every site can be different, how you configure the collection's settings will differ from one site to another.</p>
<p>Let's just say your site has a blog, with the posts stored in <code>content/blog</code>, and files saved in a date-title format, like <code>2020-09-26-how-to-make-sandwiches-like-a-pro.md</code>. Each post begins with settings in the YAML-formatted front matter in this way:</p>
<pre><code class="lang-md">---
layout: blog
title: "How to make sandwiches like a pro"
date: 2020-09-26 11:59:59
<span class="hljs-section">thumbnail: "/images/sandwich.jpg"
---</span>

This is the post body where I write about how to make a sandwich so good that will impress Gordon Ramsay.
</code></pre>
<p>With this example above, this is how you will add <code>collections</code> settings to your Netlify CMS <code>config.yml</code> file:</p>
<pre><code class="lang-yml"><span class="hljs-attr">collections:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">"blog"</span>
    <span class="hljs-attr">label:</span> <span class="hljs-string">"Blog"</span>
    <span class="hljs-attr">folder:</span> <span class="hljs-string">"content/blog"</span>
    <span class="hljs-attr">create:</span> <span class="hljs-literal">true</span>
    <span class="hljs-attr">slug:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{year}}</span>-<span class="hljs-template-variable">{{month}}</span>-<span class="hljs-template-variable">{{day}}</span>-<span class="hljs-template-variable">{{slug}}</span>"</span>
    <span class="hljs-attr">fields:</span>
      <span class="hljs-bullet">-</span> {<span class="hljs-attr">label:</span> <span class="hljs-string">"Layout"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"layout"</span>, <span class="hljs-attr">widget:</span> <span class="hljs-string">"hidden"</span>, <span class="hljs-attr">default:</span> <span class="hljs-string">"blog"</span>}
      <span class="hljs-bullet">-</span> {<span class="hljs-attr">label:</span> <span class="hljs-string">"Title"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"title"</span>, <span class="hljs-attr">widget:</span> <span class="hljs-string">"string"</span>}
      <span class="hljs-bullet">-</span> {<span class="hljs-attr">label:</span> <span class="hljs-string">"Publish Date"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"date"</span>, <span class="hljs-attr">widget:</span> <span class="hljs-string">"datetime"</span>}
      <span class="hljs-bullet">-</span> {<span class="hljs-attr">label:</span> <span class="hljs-string">"Body"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"body"</span>, <span class="hljs-attr">widget:</span> <span class="hljs-string">"markdown"</span>}
</code></pre>
<p>Let's examine what each of these fields does:</p>
<ul>
<li><code>name</code>:  This one is used in routes like /admin/collections/blog</li>
<li><code>label</code>: This one is used in the UI (User Interface). When you are in the admin page, you will see a big word "Blog" on the top of the screen. That big word "Blog" is the label.</li>
<li><code>folder</code>: This one points to the file path where your blog posts are stored.</li>
<li><code>create</code>: This one lets the user (you or whoever has admin access) create new documents (blog posts in this case) in these collections.</li>
<li><code>slug</code>: This one is the template for filenames. <code>{{year}}</code>, <code>{{month}}</code>, and <code>{{day}}</code> which are pulled from the post's date field or save date. <code>{{slug}}</code> is a URL-safe version of the post's title. By default it is <code>{{slug}}</code>.</li>
</ul>
<p>The fields are where you can customize the content editor (the page where you write the blog post). You can add stuff like ratings (1-5), featured images, meta descriptions, and so on.</p>
<p>For instance, in this particular code, we add curly braces <code>{}</code>. Inside them we write <code>label</code> with the value "Publish Date" which will be the label in the editor UI. </p>
<p>The <code>name</code> field is the name of the field in the front matter and we name it "date" since the purpose of this field is to enter the date input.</p>
<p>And lastly, the widget determines how the UI style will look and the type of data we can enter. In this case, we wrote <code>"datetime"</code> which means we can only enter the date and time.</p>
<pre><code class="lang-yml"><span class="hljs-bullet">-</span> {<span class="hljs-attr">label:</span> <span class="hljs-string">"Publish Date"</span>, <span class="hljs-attr">name:</span> <span class="hljs-string">"date"</span>, <span class="hljs-attr">widget:</span> <span class="hljs-string">"datetime"</span>}
</code></pre>
<p>You can check the list right <a target="_blank" href="https://www.netlifycms.org/docs/widgets/">here</a> to see what exactly you can add. If you want, you can even create your own widgets, too. For the sake of brevity, we'll try to keep things simple here.</p>
<h3 id="heading-enable-authentication">Enable Authentication</h3>
<p>At this point, we are nearly done with the installation and configuration of Netlify CMS. Now it's time to connect your Gatsby site to the CMS by enabling authentication. </p>
<p>We'll add some HTML code and then activate some features from Netlify. After that, you are on the way to creating your first blog post.</p>
<p>We are going to need a way to connect a front end interface to the backend so that we can handle authentication. To do that, add this HTML script tag to two files:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://identity.netlify.com/v1/netlify-identity-widget.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>The first file to add this script tag is the <code>admin/index.html</code> file. Place it between the <code>&lt;head&gt;</code> tags. And the second file to add the tag is the <code>public/index.html</code> file. This one also goes in between the <code>&lt;head&gt;</code> tags.</p>
<p>When a user logs in with the Netlify Identity widget, an access token directs them to the site homepage. In order to complete the login and get back to the CMS, redirect the user back to the <code>/admin/</code> path.</p>
<p>To do this, add the following code before the closing <code>body</code> tag of the <code>public/index.html</code> file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">window</span>.netlifyIdentity) {
    <span class="hljs-built_in">window</span>.netlifyIdentity.on(<span class="hljs-string">"init"</span>, <span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (!user) {
        <span class="hljs-built_in">window</span>.netlifyIdentity.on(<span class="hljs-string">"login"</span>, <span class="hljs-function">() =&gt;</span> {
          <span class="hljs-built_in">document</span>.location.href = <span class="hljs-string">"/admin/"</span>;
        });
      }
    });
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>With this, we are now done writing the code and it's time to visit Netlify to activate authentication.</p>
<p>Before we move on, you should Git commit your changes and push them to the repository. Plus, you will have to deploy your site live so you can access the features in the Enable Identity and Git Gateway section.</p>
<h2 id="heading-deploy-your-site-live-with-netlify">Deploy your site live with Netlify</h2>
<p>We are going to use Netlify to deploy our Gatsby site live. The deployment process is pretty straightforward, quick, and most importantly, it comes with a free SSL (Secure Sockets Layer). This means your site is protected (you can tell by looking at the green lock on the browser search).</p>
<p>If you haven't signed up for the platform, you can do it <a target="_blank" href="https://app.netlify.com/signup?_ga=2.69477016.986166254.1601369549-1254573554.1571849986">right here</a>. When you've finished signing up, you can begin the deployment process by following these 3 steps.</p>
<ol>
<li>Click the "New site from Git" button to create a new site to be deployed. Choose the Git provider where your site is hosted. My site is hosted on GitHub so that's what I will choose.</li>
<li>Choose the repository you want to connect to Netlify. The name of my Gatsby site is "foodblog" but you have to pick your own project name.</li>
<li>The last one asks how you would like Netlify to adjust your builds and deploy your site. We are going to leave everything as it is and we will click the "Deploy site" button. This will begin deploying your site to live.</li>
</ol>
<p>Once the deployment is complete, you can visit your live site by clicking the green link that has been generated for you on the top left of the screen. Example: <code>https://random_characters.netlify.app</code>.</p>
<p>With this, the world can now view your site. You can replace the weird URL with your custom domain by reading this <a target="_blank" href="https://docs.netlify.com/domains-https/custom-domains/#definitions">documentation</a>.</p>
<h3 id="heading-how-to-enable-identity-and-git-gateway">How to enable Identity and Git Gateway</h3>
<p>Netlify's Identity and Git Gateway services help you manage CMS admin users for your site without needing them to have an account with your Git host (Like GitHub) or commit access on your repository.</p>
<p>To activate these services, head to your site dashboard on Netlify and follow these steps:</p>
<ol>
<li>Go to <strong>Settings</strong> &gt; <strong>Identity</strong>, and select <strong>Enable Identity</strong> service.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--34-.png" alt="Image" width="600" height="400" loading="lazy">
<em>In the Overview page of your site, click the "Settings" link.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--36-.png" alt="Image" width="600" height="400" loading="lazy">
<em>After clicking "Settings", scroll down the left sidebar and click the "Identity" link.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--37-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Click the "Enable Identity" button to activate the Identity feature.</em></p>
<ol start="2">
<li>Under <strong>Registration</strong> preferences, select <strong>Open</strong> or <strong>Invite only</strong>. Most of the time, you want only invited users to access your CMS. But if you are just experimenting, you can leave it open for convenience.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--38-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Under the Identity submenu, click the "Registration" link and you'll be taken to the registration preferences.</em></p>
<ol start="3">
<li>Scroll down to <strong>Services</strong> &gt; <strong>Git Gateway</strong>, and click <strong>Enable Git Gateway</strong>. This authenticates with your Git host and generates an API access token. </li>
</ol>
<p>In this case, we're leaving the <strong>Roles</strong> field blank, which means any logged-in user may access the CMS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--40-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Under the Identity submenu, click the "Services" link.</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--41-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Click the "Enable Git Gateway" button to activate the Git Gateway feature.</em></p>
<p>With this, your Gatsby site has been connected with Netlify CMS. All that is left is to access the CMS admin and write blog posts.</p>
<h2 id="heading-how-to-access-the-cms">How to access the CMS</h2>
<p>All right, you are now ready to write your first blog post!</p>
<p>There are two ways to access your CMS admin, depending on what accessing options you chose from the Identity.</p>
<p>If you selected <strong>Invite only</strong>, you can invite yourself and other users by clicking the Invite user button. Then an email message will be sent with an invitation link to login to your CMS admin. Click the confirmation link and you'll be taken to the login page.</p>
<p>Alternatively, if you selected <strong>Open</strong>, you can access your site's CMS directly at <code>yoursite.com/admin/</code>. You will be prompted to create a new account. When you submit it, a confirmation link will be sent to your email. Click the confirmation link to complete the signup process and you'll be taken to the CMS page.</p>
<p><strong>Note</strong>: If you cannot access your CMS admin after clicking the link from the email, the solution is to copy the link in the browser starting with <code>#confirmation_token=random_characters</code> and paste the link after the hashtag "#", like this: <code>https://yoursite.com/admin/#confirmation_token=random_characters</code>. This should fix the problem.</p>
<p>If everything goes well, you should see your site's admin dashboard:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/10/Screenshot--42-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Netlify CMS admin.</em></p>
<p>You can create your new post by clicking the "New post" button.</p>
<p>When you're ready to publish your post, you can click the "Publish Now" button to publish it immediately.</p>
<p>When you hit the publish button, the post file is automatically created. Then it will add to the changes with the commit message based on the name of the post along with the date and time of publishing. Finally, it will be pushed to the host repository, and from there your post will be seen live.</p>
<p>You can view the changes by looking at the commit message in your host repository.</p>
<p>After waiting for a few minutes, your new post should be live.</p>
<h3 id="heading-one-more-thing">One more thing</h3>
<p>The last thing to do is clean up the sample articles. To delete these posts, go to the blog files in your text editor and delete them one by one. Make sure you check your terminal when deleting them so that there will be no issues on your site.</p>
<p>Once all the sample posts are cleared out, commit these changes and push them to the repository.</p>
<p>And now, you are all done! You can now create your new posts from the comfortable CMS dashboard and share your stories to the world.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this guide you have learned how to:</p>
<ul>
<li>Create a Gatsby blog site</li>
<li>Added the Netlify CMS to your Gatsby site by creating and configuring files</li>
<li>Enable user authentication by activating Identity and Git Gateway</li>
<li>Access your site's CMS admin</li>
<li>Publish your first post powered by Gatsby and Netlify CMS</li>
</ul>
<p>By the end of this guide, you should now be able to enjoy writing blog posts with a fast website and simple content editor. And you probably don't have to touch the code unless it needs further customization.</p>
<p>There is still more to cover about Gatsby and Netlify CMS. One of the best ways to learn about them is to go through their documentation.</p>
<p>I hope you found this guide beneficial, and happy posting!</p>
<p><a target="_blank" href="https://www.mohammedasker.com/">Check out my blog</a> to learn more tips, tricks, and tutorials about web development.</p>
<p>Cover photo by <a target="_blank" href="https://unsplash.com/@neonbrand?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">NeONBRAND</a> on <a target="_blank" href="https://unsplash.com/s/photos/blogging?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>.</p>
<h3 id="heading-resources-for-javascript-and-react">Resources for JavaScript and React</h3>
<p>Here are some resources that may help you to learn JavaScript and React:</p>
<p><strong>JavaScript</strong></p>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">Official JavaScript Documentation</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/">freeCodeCamp</a></li>
<li><a target="_blank" href="https://www.w3schools.com/js/">W3Schools: JavaScript Tutorial</a></li>
<li><a target="_blank" href="https://javascript.info/">JavaScript.info</a></li>
</ul>
<p><strong>React</strong></p>
<ul>
<li><a target="_blank" href="https://reactjs.org/docs/getting-started.html">Official React Documentation</a></li>
<li><a target="_blank" href="https://www.udemy.com/course/complete-react-developer-zero-to-mastery/">Complete React Developer in 2020 (w/ Redux, Hooks, GraphQL)</a></li>
<li><a target="_blank" href="https://scrimba.com/learn/learnreact">Scrimba: Learn React for free</a></li>
<li><a target="_blank" href="https://flaviocopes.com/page/react-handbook/">Flavio Copes: The React Handbook</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ WordPress Alternatives – How to Choose the Right CMS for Your Site ]]>
                </title>
                <description>
                    <![CDATA[ By Yehuda Clinton WordPress is powerful and versatile and it powers more of the internet's web pages than any other engine. But it's not a perfect fit for everyone. And perhaps you're looking for something different. So let me help guide you through ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/wordpress-alternatives-2020/</link>
                <guid isPermaLink="false">66d4617737bd2215d1e245fe</guid>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 19 Aug 2020 16:21:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/cms.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yehuda Clinton</p>
<p>WordPress is powerful and versatile and it powers more of the internet's web pages than any other engine.</p>
<p>But it's not a perfect fit for everyone. And perhaps you're looking for something different. So let me help guide you through the confusing world of modern web Content Management.</p>
<p>To do this we'll compare the top Content Management Systems (CMS) built from each of the three dominant programming language families: PHP, Node, and Python.</p>
<p>All the options I’ll explore are open source. Which is fitting, since in many ways, WordPress was a pioneer in open source platforms.</p>
<p>However, some of us are looking for a more modern, faster, more secure CMS. And we still don’t like the closed-source ones like Squarespace and Wix.</p>
<p>What seems to be happening is that people are moving away from CMS platforms built on a single engine, <a target="_blank" href="https://www.freecodecamp.org/news/simplified-explanation-to-mvc-5d307796df30/">MVC</a> paradigm to a more decoupled system.</p>
<p>For example, does your website's blog really need a full database? And could your eCommerce or payment system use a simpler <a target="_blank" href="https://www.mobify.com/insights/headless-commerce/">headless paradigm</a>?</p>
<p>So let's see what's available, arranged by language.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/image-102.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-php">PHP</h2>
<p>PHP is a simple, reliable and well maintained language. So it's no surprise that it came to be the most popular backend of the entire web.</p>
<p>Its versatility makes it easy for developers to provide such large arrays of features and plugins for their CMS's. In short, PHP was basically originally <a target="_blank" href="https://www.elated.com/cms-in-an-afternoon-php-mysql/">invented for the CMS</a>.</p>
<p>A downside to WordPress's popularity is that its plugin marketplace is hard to navigate or, in some cases, maybe it's too expensive.</p>
<p>However, WordPress may not be unique in that sense. Here are some other PHP CMS frameworks:</p>
<ul>
<li><p><strong>Drupal</strong></p>
</li>
<li><p><strong>Joomla</strong></p>
</li>
<li><p><strong>Magento</strong></p>
</li>
<li><p><strong>Grav CMS</strong></p>
</li>
</ul>
<p>The first three all have the same issue as WordPress: a bloated interface or an overcrowded plugin marketplace.</p>
<p>But Grav felt like a breath of fresh air. It's a bit like a simplified WordPress without all the complex bloatware. There isn't even a database, just folders and pages.</p>
<p>It attempts to give you the best of both worlds. Grav has an admin dashboard plugin for non techies to manage everything as they would with WordPress.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/image-104.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>At the same time, Grav also delivers the stability and customization of a decoupled system. You don't even need an admin GUI if you don't want it.</p>
<h2 id="heading-node">Node</h2>
<p>Node.js, the newest language to hit the back end market, is innovative and unconventional. Since it's already a popular language for front end web development, it seems like Node is making a play for most popular programming language everywhere.</p>
<p>Node deployments often rely on tech stacks such as NoSQL databases such as MongoDB, NGINX web servers, and Markdown. An advantage of a Node.js-powered CMS is that it tends to integrate well with web apps.</p>
<p>Here are a couple of Node.js based CMS's:</p>
<ul>
<li><p><strong>KeystoneJs</strong>: Complex. More of a framework than a CMS.</p>
</li>
<li><p><strong>Ghost</strong>: Simple. Doesn’t do much more than Medium, which is perfect if you want to self host your Medium blog. You can add decoupled eCommerce like Shopify.</p>
</li>
<li><p><strong>NetlifyCMS</strong>: Not a standalone CMS – rather, you add it to a website/webapp as a custom git-based static content manager for your writers.</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/image-105.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>From a market-share perspective, Ghost seems to be the only new CMS that is <a target="_blank" href="https://www.datanyze.com/market-share/wcms--7/ghost-vs-wordpress">positioned to take a bite out of the WordPress monopoly</a>.</p>
<h2 id="heading-python">Python</h2>
<p>Although Python is known as a powerful scripting language, in recent years it has matured to be an all around server-side language. However it still has a much less developed plugin and themes market for its CMSs.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/image-106.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here are a few popular Python based CMS platforms:</p>
<ul>
<li><p><strong>Django CMS</strong>: Requires a bit more code know-how than WordPress</p>
</li>
<li><p><strong>Mezzanine</strong>: Also built on Django. Many features, but you still need to know Python for advanced functionality.</p>
</li>
<li><p><strong>Storyblok</strong>: friendly editor interface and headless api for apps but limited plugins</p>
</li>
</ul>
<p>Python has the advantage of speed in certain situations. And so Python frameworks will potentially scale up much more efficiently than JavaScript. Also this is why they will often run better on inexpensive hardware such as a Raspberry Pi.</p>
<p>These Python-based CMSs might also find their niche when integrating with a domain that is dominated by Python. What areas are we talking about here? Check out this article and find out <a target="_blank" href="https://www.freecodecamp.org/news/what-is-python-used-for-10-coding-uses-for-the-python-programming-language/">what Python is used for</a>.</p>
<p>All the same, I doubt Python will ever be a major contender in the CMS market. Mainly because it came very late to the web. The lack of backwards compatibility between versions is an issue as well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>If you are ready to embrace the future of the CMS, here are the keys to making an informed decision.</p>
<p>Consider all the factors that will most likely give you all the security, reliability, and customization you need.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Travel Bucket List Map with Gatsby, React Leaflet, & Hygraph ]]>
                </title>
                <description>
                    <![CDATA[ Traveling is fun and we all have a lot of places we want to visit, but rarely do we have time to do it all at once. That’s what bucket lists are for! How can we create a custom mapping app that we can show all of our the destinations ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-travel-bucket-list-map-with-gatsby-react-leaflet-graphcms/</link>
                <guid isPermaLink="false">66b8e3580cedc1f2a4f7069b</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Gatsby ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GatsbyJS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ graphcms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ headless cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ leaflet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mapping ]]>
                    </category>
                
                    <category>
                        <![CDATA[ maps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react-leaflet ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Travel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Colby Fayock ]]>
                </dc:creator>
                <pubDate>Tue, 23 Jun 2020 14:45:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/travel-bucket-list.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Traveling is fun and we all have a lot of places we want to visit, but rarely do we have time to do it all at once. That’s what bucket lists are for! How can we create a custom mapping app that we can show all of our the destinations on our bucket list?</p>
<p>Note: As of July 2022, GraphCMS is now <a target="_blank" href="https://hygraph.com/">Hygraph</a>.</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-are-we-going-to-build">What are we going to build?</a></li>
<li><a class="post-section-overview" href="#heading-step-1-creating-a-new-app-with-gatsby-starter-leaflet">Step 1: Creating a new app with Gatsby Starter Leaflet</a></li>
<li><a class="post-section-overview" href="#heading-step-2-creating-and-managing-a-list-of-travel-locations-with-graphcms">Step 2: Creating and managing a list of travel locations with GraphCMS</a></li>
<li><a class="post-section-overview" href="#heading-step-3-querying-our-graphcms-location-data-with-gatsby-and-graphql">Step 3: Querying our GraphCMS location data with Gatsby and GraphQL</a></li>
<li><a class="post-section-overview" href="#heading-step-4-creating-a-bucket-list-of-destinations-and-adding-them-to-the-map">Step 4: Creating a bucket list of destinations and adding them to the map</a></li>
<li><a class="post-section-overview" href="#heading-what-else-other-features-can-we-add-to-our-app">What else other features can we add to our app?</a></li>
<li><a class="post-section-overview" href="#heading-want-to-learn-more-about-maps">Want to learn more about maps?</a></li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/isbr52VKjb0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-what-are-we-going-to-build">What are we going to build?</h2>
<p>We’re going to build a mapping app with <a target="_blank" href="https://www.gatsbyjs.org/">Gatsby</a> managed by a CMS that will both display markers on a map and show our locations in a simple text-based list for our bucket list locations.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/travel-bucket-list-demo.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Demo of a Travel Bucket List mapping app</em></p>
<p>We’ll spin up the app with a <a target="_blank" href="https://github.com/colbyfayock/gatsby-starter-leaflet">Gatsby Starter for Leaflet</a> and then we’ll use <a target="_blank" href="https://graphcms.com/">GraphCMS</a> to create and manage the list of locations for our map!</p>
<h2 id="heading-woah-a-mapping-app">Woah, a mapping app?</h2>
<p>Yup. If you haven't played with maps before, don't be discouraged! It's not as bad as you probably think. If you'd rather start with mapping basics, you can  <a target="_blank" href="https://www.freecodecamp.org/news/easily-spin-up-a-mapping-app-in-react-with-leaflet/">read more about how mapping works</a>  first.</p>
<h2 id="heading-step-1-creating-a-new-app-with-gatsby-starter-leaflet">Step 1: Creating a new app with Gatsby Starter Leaflet</h2>
<p>We’ll start off with Gatsby Starter Leaflet. This is going to give us a basic React application with our mapping tools already built in.</p>
<h3 id="heading-creating-a-new-gatsby-app-with-gatsby-starter-leaflet">Creating a new Gatsby app with Gatsby Starter Leaflet</h3>
<p>To get started, navigate to where you want to create your new app and run:</p>
<pre><code class="lang-shell">gatsby new my-travel-bucket-list https://github.com/colbyfayock/gatsby-starter-leaflet
</code></pre>
<p><em>Note: you can replace <code>my-travel-bucket-list</code> with whatever you want. This will be used to create the new folder for the app.</em></p>
<p>Once you run that, Gatsby will pull down the Starter and install the dependencies. After it’s complete, navigate to that directory and run the development command:</p>
<pre><code class="lang-shell">cd my-travel-bucket-list
yarn develop
# or
npm run develop
</code></pre>
<p>Once it’s finished location, your app should be ready to go!</p>
<h3 id="heading-cleaning-our-some-demo-code">Cleaning our some demo code</h3>
<p>Because we’re using a Starter, it has a little bit of demo code. Let’s clean that out to avoid any confusion.</p>
<p>Open up the <code>src/pages/index.js</code> file.</p>
<p>First, remove everything inside of <code>mapEffect</code> except the first line and set up an alias for <code>leafletElement</code> to <code>map</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mapEffect</span>(<span class="hljs-params">{ leafletElement: map } = {}</span>) </span>{
  <span class="hljs-keyword">if</span> ( !map ) <span class="hljs-keyword">return</span>;
}
</code></pre>
<p>With that gone, we can remove the <code>markerRef</code> definition at the top of the <code>IndexPage</code> component, remove the <code>ref={markerRef}</code> prop from our <code>&lt;Marker&gt;</code> component, and the <code>useRef</code> import next to React.</p>
<p>Now, we can remove all of the variables that start with <code>popup</code> and <code>time</code>, including:</p>
<ul>
<li>timeToZoom</li>
<li>timeToOpenPopupAfterZoom</li>
<li>timeToUpdatePopupAfterZoom</li>
<li>popupContentHello</li>
<li>popupContentGatsby</li>
</ul>
<p>Lastly, you can remove all of the following lines:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> L <span class="hljs-keyword">from</span> <span class="hljs-string">'leaflet'</span>;
...
import { promiseToFlyTo, getCurrentLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">'lib/map'</span>;
...
import gatsby_astronaut <span class="hljs-keyword">from</span> <span class="hljs-string">'assets/images/gatsby-astronaut.jpg'</span>;
...
const ZOOM = <span class="hljs-number">10</span>;
</code></pre>
<p>Once done, we should be ready to go with a basic app with a map!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/new-app-gatsby-starter-leaflet.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New app with Gatsby Starter Leaflet</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-travel-bucket-list/commit/63eed5a7a208ede6f8eeec44e0c08b594b407360">Follow along with the commit!</a></p>
<h2 id="heading-step-2-creating-and-managing-a-list-of-travel-locations-with-graphcms">Step 2: Creating and managing a list of travel locations with GraphCMS</h2>
<h3 id="heading-creating-a-graphcms-account">Creating a GraphCMS account</h3>
<p>To get started with GraphCMS, you’ll need an account. I’m not going to walk you through this part, but the good news is they have a generous free tier that makes it easy to sign up for us to use for our demo!</p>
<p><a target="_blank" href="https://app.graphcms.com/signup">Sign up for GraphCMS</a></p>
<p>Alternatively, if you already have an account, you can make sure you’re logged in.</p>
<h3 id="heading-creating-a-new-graphcms-project">Creating a new GraphCMS project</h3>
<p>Once logged in, we’ll want to create a new project. We’re going to create one manually, so once at the <a target="_blank" href="https://app.graphcms.com/">GraphCMS Dashboard</a>, select <strong>Create new project</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-create-new-project.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a new project in GraphCMS</em></p>
<p>Here, you can enter whatever you’d like for the <strong>Name</strong> and <strong>Description</strong> such as:</p>
<ul>
<li>Name: My Travel Bucket List</li>
<li>Description: The locations that I want to travel to some day!</li>
</ul>
<p>Below that you’ll see a map where you’ll select a <strong>Region</strong>. This is where your database data will live, so while it probably doesn’t matter too much for our purposes, you can choose the one that’s closest to you.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-configure-new-project.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring a new project in GraphCMS</em></p>
<p>After you select your options, go ahead and click <strong>Create Project</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-select-plan.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting the Personal plan in GraphCMS</em></p>
<p>Next, you’ll be presented with billing options. Since we’re just creating a demo, under <strong>Personal</strong> select <strong>Continue</strong> at which point we’ll be dropped into our new GraphCMS project dashboard.</p>
<h3 id="heading-creating-a-new-content-model-schema-with-graphcms">Creating a new Content Model Schema with GraphCMS</h3>
<p>In GraphCMS, a Content Model refers to a specific type of data that has specific properties associated with it. In our case, our Model will be a Destination, which will be defined by a Name and a Location.</p>
<p>First, navigate to the <strong>Schema</strong> section of GraphCMS in the left sidebar and select <strong>Create Model</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-create-new-schema-model.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a new Schema Model in GraphCMS</em></p>
<p>Once selected, you’ll see a popup that asks for a bit more information. Here, you can type in “Destination” as the <strong>Display Name</strong>, which will also fill in most of the other fields. We’ll leave those as is.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-configure-new-content-model.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring a new Model in GraphCMS</em></p>
<p>Feel free to add a description if you’d like, but it’s not required. Then select <strong>Create model</strong>.</p>
<p>Now that we have our Model, we need our properties.</p>
<p>First, select <strong>Single line text</strong> in the right list of fields and add a <strong>Display Name</strong> of “Name”. This will also fill out <strong>App Id</strong> which you can leave as is. Then click <strong>Create</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-configure-text-field.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding and configuring a new text field in GraphCMS</em></p>
<p>Next, scroll down in the field options on the right and under <strong>Location</strong> select <strong>Map</strong>. Add “Location” as the <strong>Display Name</strong>, which will set the <strong>App Id</strong> as “location” which you can leave as is. Then same as before, click <strong>Create</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-configure-new-map-field.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding and configuring a new map field in GraphCMS</em></p>
<p>Now we have a Content Model which we’ll use to create our locations!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-destination-content-model.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Destination content Model in GraphCMS</em></p>
<h3 id="heading-creating-our-locations">Creating our locations</h3>
<p>Finally, let’s create our locations. Navigate over to <strong>Content</strong> in the GraphCMS dashboard, make sure you’ve selected <strong>Destination</strong> under <strong>System</strong> (should be the only one), and select <strong>Create New</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-add-new-content.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Create new Destination Content in GraphCMS</em></p>
<p>Now we can start adding all of our locations! First, add the name of your location in the <strong>Name</strong> field, then you can use the <strong>Search</strong> box under <strong>Location</strong> to find that location on the map.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-create-new-destination-content-item.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Adding a new Destination Content item in GraphCMS</em></p>
<p>Once you’re good, hit <strong>Save and publish</strong>. This will create your first location!</p>
<p>Follow those same steps and create as many locations as you want.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-destination-content-items.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>List of Destination Content items in GraphCMS</em></p>
<p>We’ll use these for our map and bucket list.</p>
<h2 id="heading-step-3-querying-our-graphcms-location-data-with-gatsby-and-graphql">Step 3: Querying our GraphCMS location data with Gatsby and GraphQL</h2>
<p>Now that we have our locations, let’s use them!</p>
<h3 id="heading-adding-a-plugin-to-gatsby-to-query-our-graphql-data">Adding a plugin to Gatsby to query our GraphQL data</h3>
<p>First, we need to <a target="_blank" href="https://www.gatsbyjs.org/packages/gatsby-source-graphql/">add a new plugin</a> to our Gatsby project to query our GraphQL data. In your terminal make sure your development server isn’t running and run:</p>
<pre><code class="lang-shell">yarn add gatsby-source-graphql
# or
npm install gatsby-source-graphql
</code></pre>
<p>Next, open up your <code>gatsby-config.js</code> file in the root of your project and add the following to your plugins:</p>
<pre><code class="lang-json">{
  resolve: 'gatsby-source-graphql',
  options: {
    typeName: 'GCMS',
    fieldName: 'gcms',
    url: '[API ENDPOINT]',
  }
}
</code></pre>
<p>This will be what sources our data from GraphCMS, but we need an endpoint.</p>
<h3 id="heading-finding-our-api-endpoint-for-graphcms">Finding our API endpoint for GraphCMS</h3>
<p>Open back up your browser and head over to your GraphCMS project. After selecting <strong>Settings</strong> in the left navigation, select <strong>API Access</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-api-access.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>API Access in GraphCMS</em></p>
<p>Before we copy our API Endpoint, first we need to update our permissions so we can query our API. Under <strong>Public API Permissions</strong>, check the box next to <strong>Content from stage Published</strong> and click <strong>Save</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-configure-api-access.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Configuring API permissions in GraphCMS</em></p>
<p>Next, copy the URL under <strong>Endpoints</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/graphcms-copy-api-access-endpoint.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Copying API Endpoint in GraphCMS</em></p>
<p>And paste that in to your <code>gatsby-config.js</code> file that we modified above:</p>
<pre><code class="lang-json">{
  resolve: 'gatsby-source-graphql',
  options: {
    typeName: 'GCMS',
    fieldName: 'gcms',
    url: 'https:<span class="hljs-comment">//[region-id].graphcms.com/v2/[project-id]/master',</span>
  },
},
</code></pre>
<p><em>Note: your URL will have actual values inside of <code>[region-id]</code> and <code>[project-id]</code>.</em></p>
<p>Save your <code>gatsby-config.js</code> file and start your development server backup (<code>yarn develop</code>) and we’re ready to go!</p>
<h3 id="heading-querying-our-locations-via-graphql">Querying our locations via GraphQL</h3>
<p>Finally, let’s actually query our data so that we’ll be able to use it in our app.</p>
<p>We’re going to create a new <a target="_blank" href="https://reactjs.org/docs/hooks-reference.html">React Hook</a> that we’ll be able to use to grab our locations anywhere within our app.</p>
<p>Under <code>src/hooks/index.js</code>, add the following line to the existing list:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> { <span class="hljs-keyword">default</span> <span class="hljs-keyword">as</span> useDestinations } <span class="hljs-keyword">from</span> <span class="hljs-string">'./useDestinations'</span>;
</code></pre>
<p>This will allow us to more conveniently import our hook which we’ll create next.</p>
<p>Under <code>src/hooks</code>, create a new file <code>useDestinations.js</code> and paste in this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { graphql, useStaticQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'gatsby'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useDestinations</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { gcms = {} } = useStaticQuery( graphql<span class="hljs-string">`
    query {
      gcms {
        destinations {
          id
          name
          location {
            latitude
            longitude
          }
        }
      }
    }
  `</span> );

  <span class="hljs-keyword">let</span> { destinations } = gcms;

  <span class="hljs-keyword">return</span> {
    destinations,
  };
}
</code></pre>
<p>Here, we’re:</p>
<ul>
<li>Importing the <code>graphql</code> and <code>useStaticQuery</code> utilities from Gatsby</li>
<li>We’re creating a new function (or hook) that is exported by default</li>
<li>In that function, we’re using <code>useStaticQuery</code> to create a new GraphQL query which asks GraphCMS to return the data structure we defined.</li>
<li>That query returns a value which we destructure immediately to grab the <code>gmcs</code> object</li>
<li>We destructure <code>destinations</code> from <code>gmcs</code> and return it as part of a new object from our hook</li>
</ul>
<p>With this, we can now use our hook anywhere in our app!</p>
<p>Head over to your <code>src/pages/index.js</code> file, first import our new hook:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useDestinations } <span class="hljs-keyword">from</span> <span class="hljs-string">'hooks'</span>;
</code></pre>
<p>And at the top of the <code>IndexPage</code> component, query our data:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { destinations } = useDestinations();
</code></pre>
<p>This puts all of our locations into the <code>destinations</code> variable. We can test that this works by console logging it out:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'destinations'</span>, destinations);
</code></pre>
<p>And once we open up our browser and look in our web developer tools console, we can see our location data!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/gatsby-starter-leaflet-logging-graphcms-destinations.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Logging destinations data to the web console</em></p>
<h2 id="heading-step-4-creating-a-bucket-list-of-destinations-and-adding-them-to-the-map">Step 4: Creating a bucket list of destinations and adding them to the map</h2>
<p>We’re going to start with creating a simple text list of our destinations. This will let us see all of our destinations in an easy to read format.</p>
<h3 id="heading-creating-a-text-list-of-our-destinations">Creating a text list of our destinations</h3>
<p>Inside of our <code>IndexPage</code> and above “Still Getting Started?”, let’s add the following code:</p>
<pre><code class="lang-jsx">&lt;h2&gt;My Destinations&lt;/h2&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  { destinations.map(destination =&gt; {
    const { id, name } = destination;
    return <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span>&gt;</span>{ name }<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  })}
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
</code></pre>
<p>This code:</p>
<ul>
<li>Adds a new header for our list</li>
<li>Creates a new unordered list</li>
<li>Loops through our <code>destinations</code> and creates a new list item for each destination that include’s the location’s name</li>
</ul>
<p>Once we hit save and reload, we should see our list under our map!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/app-adding-list-of-destinations.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New basic list of destinations in the app</em></p>
<p>The list looks a little odd though right? We probably want to format it a little better to fit into the page.</p>
<p>Open up <code>src/assets/stylesheets/pages/_home.scss</code> and inside of the <code>.home-start</code> class, add:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.home-start</span> {

  ...

  <span class="hljs-selector-tag">ul</span> {
    <span class="hljs-attribute">list-style</span>: none;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">1.2em</span> <span class="hljs-number">0</span>;
  }
</code></pre>
<p>Let’s also modify the <code>h2</code> to space things out a little better:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.home-start</span> {

  ...

  <span class="hljs-selector-tag">h2</span> {

    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2em</span>;

    &amp;<span class="hljs-selector-pseudo">:first-child</span> {
      <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0</span>;
    }

  }
</code></pre>
<p>Once you hit save and reload, it should look a little better.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/app-fixing-styles-list-of-destinations.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Destinations in the app with cleaned up styles</em></p>
<p>Feel free to make additional changes, but we’ll leave it there for now.</p>
<h3 id="heading-adding-our-destinations-to-the-map">Adding our destinations to the map</h3>
<p>Now we can finally add our destinations to the map!</p>
<p>Inside of our <code>&lt;Map&gt;</code> component, we already have a <code>&lt;Marker&gt;</code>. This allows us to easily add a marker to the map given a position. We’ll take this concept and combine it with our text list to add our locations to the map.</p>
<p>Let’s update our <code>&lt;Map&gt;</code> code to match the following:</p>
<pre><code class="lang-jsx">&lt;<span class="hljs-built_in">Map</span> {...mapSettings}&gt;
  { destinations.map(<span class="hljs-function"><span class="hljs-params">destination</span> =&gt;</span> {
    <span class="hljs-keyword">const</span> { id, name, location } = destination;
    <span class="hljs-keyword">const</span> position = [location.latitude, location.longitude];
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Marker</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span> <span class="hljs-attr">position</span>=<span class="hljs-string">{position}</span> /&gt;</span></span>
  })}
&lt;/<span class="hljs-built_in">Map</span>&gt;
</code></pre>
<p>Here we:</p>
<ul>
<li>Loop through our <code>destinations</code> to dynamically create a new list of components inside our <code>&lt;Map&gt;</code></li>
<li>Inside each loop instance, we destructure our date from <code>destination</code></li>
<li>We create a new <code>position</code> array with the latitude and longitude</li>
<li>Create a new <code>Marker</code> where we use our position to add it to the map</li>
</ul>
<p>This gives us our markers on the map!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/mapping-app-with-destination-markers.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Markers for each destination in the mapping app</em></p>
<p>But we want to know what each of those locations are, so let’s also add a popup to each marker that will show the name.</p>
<p>First, we need to import <code>Popup</code> from <code>react-leaflet</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Marker, Popup } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-leaflet'</span>;
</code></pre>
<p>Then, let’s update our <code>&lt;Marker&gt;</code> component to return:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Marker</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{id}</span> <span class="hljs-attr">position</span>=<span class="hljs-string">{position}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Popup</span>&gt;</span>{ name }<span class="hljs-tag">&lt;/<span class="hljs-name">Popup</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Marker</span>&gt;</span></span>
);
</code></pre>
<p>And once we save and open back up our map, you can now click on each marker and see our destinations name!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/mapping-app-with-destination-marker-popup.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Popup for each destination marker in the mapping app</em></p>
<h3 id="heading-before-were-done-center-the-map">Before we’re done, center the map</h3>
<p>Previously, our demo map centered on Washington, DC. Let’s update that to the center of the world since our map doesn’t focus on the United States.</p>
<p>Update the <code>LOCATION</code> variable to:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> LOCATION = {
  <span class="hljs-attr">lat</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">lng</span>: <span class="hljs-number">0</span>,
};
</code></pre>
<p>And with that, we have our map!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/06/mapping-app-with-travel-bucket-list-markers.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Final mapping app with markers and popups for each destination</em></p>
<p><a target="_blank" href="https://github.com/colbyfayock/my-travel-bucket-list/commit/56dbadb74cea2770174eb8ea7c039be27ca18971">Follow along with the commit!</a></p>
<h2 id="heading-what-else-other-features-can-we-add-to-our-app">What else other features can we add to our app?</h2>
<h3 id="heading-add-a-way-to-check-off-each-location">Add a way to check off each location</h3>
<p>Inside GraphCMS, you can add a new field to your Destination content model that allows you to select whether you visited each location or not.</p>
<p>With this value, we can add it to our query and update our map with some kind of indicator like a checkmark to show that we’ve checked it off our bucket list!</p>
<h3 id="heading-customize-your-map-background-styles">Customize your map background styles</h3>
<p>We’re using a public version of <a target="_blank" href="https://www.openstreetmap.org/#map=5/38.007/-95.844">OpenStreetMap</a> which is open source, but <a target="_blank" href="https://www.mapbox.com/">Mapbox</a> offers some cool maps we can use to make it look a little more impressive.</p>
<p>If you want to get started changing your map styles, you can <a target="_blank" href="https://www.freecodecamp.org/news/how-to-set-up-a-custom-mapbox-basemap-with-gatsby-and-react-leaflet/">check out this other walkthrough</a> of mine to learn how to use Mapbox.</p>
<p><a target="_blank" href="https://www.colbyfayock.com/2020/04/how-to-set-up-a-custom-mapbox-basemap-style-with-react-leaflet-and-leaflet-gatsby-starter">Check out the blog post</a> or <a target="_blank" href="https://www.youtube.com/watch?v=KcPJr1b_rv0">watch the video</a>!</p>
<h3 id="heading-style-the-map-markers-with-a-custom-image">Style the map markers with a custom image</h3>
<p>You can check out my video walk through on how to change the markers to a custom image.</p>
<p>Take that a step further and use the feature above to dynamically show a different marker image when you’ve checked off a location.</p>
<p><a target="_blank" href="https://egghead.io/lessons/react-customize-geojson-data-markers-with-a-react-leaflet-icon-image?pl=mapping-with-react-leaflet-e0e0&amp;af=atzgap">Check out the video on Egghead.io!</a></p>
<h2 id="heading-want-to-learn-more-about-maps">Want to learn more about maps?</h2>
<p>Check out some of my other tutorials and videos:</p>
<ul>
<li><a target="_blank" href="https://egghead.io/playlists/mapping-with-react-leaflet-e0e0?af=atzgap">Mapping with React Leaflet</a> (<a target="_blank" href="https://egghead.io/?af=atzgap">egghead.io</a>)</li>
<li><a target="_blank" href="https://www.youtube.com/playlist?list=PLFsfg2xP7cbJTnTFH3OGXEAt9O1mpoqpR">Mapping Apps with React, Gatsby, &amp; Leaflet</a> (<a target="_blank" href="https://www.youtube.com/channel/UC7Wpv0Aft4NPNhHWW_JC4GQ">youtube.com</a>)</li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/03/how-to-create-a-coronavirus-covid-19-dashboard-map-app-with-gatsby-and-leaflet">How to create a Coronavirus (COVID-19) Dashboard &amp; Map App with Gatsby and Leaflet</a> (colbyfayock.com)</li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/03/how-to-create-a-summer-road-trip-mapping-app-with-gatsby-and-leaflet">How to Create a Summer Road Trip Mapping App with Gatsby and Leaflet</a> (colbyfayock.com)</li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/easily-spin-up-a-mapping-app-in-react-with-leaflet/">How to build a mapping app in React the easy way with Leaflet</a> (colbyfayock.com)</li>
<li><a target="_blank" href="https://www.colbyfayock.com/2020/03/anyone-can-map-inspiration-and-an-introduction-to-the-world-of-mapping">Anyone Can Map! Inspiration and an introduction to the world of mapping</a> (colbyfayock.com)</li>
</ul>
<h2 id="heading-whats-on-your-travel-bucket-list">What’s on your travel bucket list?</h2>
<p><a target="_blank" href="https://twitter.com/colbyfayock">Let me know on Twitter!</a></p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/colbyfayock/status/1275441134144110595"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<div id="colbyfayock-author-card">
  <p>
    <a href="https://twitter.com/colbyfayock">
      <img src="https://res.cloudinary.com/fay/image/upload/w_2000,h_400,c_fill,q_auto,f_auto/w_1020,c_fit,co_rgb:007079,g_north_west,x_635,y_70,l_text:Source%20Sans%20Pro_64_line_spacing_-10_bold:Colby%20Fayock/w_1020,c_fit,co_rgb:383f43,g_west,x_635,y_6,l_text:Source%20Sans%20Pro_44_line_spacing_0_normal:Follow%20me%20for%20more%20JavaScript%252c%20UX%252c%20and%20other%20interesting%20things!/w_1020,c_fit,co_rgb:007079,g_south_west,x_635,y_70,l_text:Source%20Sans%20Pro_40_line_spacing_-10_semibold:colbyfayock.com/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_68,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_145,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_222,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/w_300,c_fit,co_rgb:7c848a,g_north_west,x_1725,y_295,l_text:Source%20Sans%20Pro_40_line_spacing_-10_normal:colbyfayock/v1/social-footer-card" alt="Follow me for more Javascript, UX, and other interesting things!" width="2000" height="400" loading="lazy">
    </a>
  </p>
  <ul>
    <li>
      <a href="https://twitter.com/colbyfayock">? Follow Me On Twitter</a>
    </li>
    <li>
      <a href="https://youtube.com/colbyfayock">?️ Subscribe To My Youtube</a>
    </li>
    <li>
      <a href="https://www.colbyfayock.com/newsletter/">✉️ Sign Up For My Newsletter</a>
    </li>
  </ul>
</div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to solve a CMS problem when you’re caught between RESTful, WordPress, and a hard place ]]>
                </title>
                <description>
                    <![CDATA[ By Jessica Duffin Wolfe Last fall I was trying to decide on how to host and manage a small storytelling project built by around 40 users — my students. I wanted them to have a clean and easy experience uploading their content (images and audio files,... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-solve-a-cms-problem-when-youre-caught-between-restful-wordpress-and-a-hard-place-77bbebe49e1b/</link>
                <guid isPermaLink="false">66c354c75b0262f172b2c7f0</guid>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ storytelling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 19 Jun 2018 02:34:57 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*IQ9QA3Sy1kX7XdmZmFwlYg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jessica Duffin Wolfe</p>
<p>Last fall I was trying to decide on how to host and manage a small <a target="_blank" href="http://36to.ca/#/">storytelling project</a> built by around 40 users — my students. I wanted them to have a clean and easy experience uploading their content (images and audio files, along with some text). I also wanted it to be stored long-term in a format my little Vue.js app could easily pull in to display without a lot of set up and overhead on my part.</p>
<p>I’ve relied very happily on WordPress as a primary Content Management System (CMS) for years, but it’s been feeling a bit old lately, and it’s not quite designed for such a heavily AV-based, multi-user project, so I decided to look around for good fresh options.</p>
<h3 id="heading-option-1-google-sheets"><strong>Option 1: Google Sheets</strong></h3>
<p>The simplest path seemed to be setting up a Google Sheet the students could populate with links to their own self-hosted media. I’ve had good experiences building small sites like this before pulling in the data through JSON.</p>
<p>For this case, though, with around fifteen different content pieces going into each user’s contribution, if I used a spreadsheet it would be a beast, and populating it would not be a good user experience for the students.</p>
<p>The links to the students’ self-hosted media also risked going bad over time, as accounts lapse, and services dry up. I didn’t want the project to get patchy, and I didn’t want to have to do too much maintenance on it each year to keep it solid.</p>
<p>So, no to Google Sheets.</p>
<h3 id="heading-option-2-contentful"><strong>Option 2: Contentful</strong></h3>
<p><a target="_blank" href="https://www.contentful.com/">Contentful</a> is a headless CMS, which means it provides infrastructure for storing, editing, and serving content without providing any sort of front-end display. Traditional WordPress, in contrast, is set up to do both — store your content, and offer up all the code that retrieves and displays it. This big stack of abilities makes it pretty bulky, and increasingly it doesn’t feel as nimble as a web tool should.</p>
<p>I was really excited about Contentful. It’s so pretty and slick! And so smart — it permits direct geotagging of content! Ahhh. And I could set up a custom content model that exactly matched the project at hand, and it was fun! Yay.</p>
<p>After spending some time configuring Contentful, I desperately wanted to use it, but I began to lose interest the more I thought through how the students would upload their work.</p>
<p>The free tier maxes out at five users. While I could have had the students upload their content through one generic user account, this would not have been a good experience, as they would have had to wade through the back end and other people’s files to submit their work.</p>
<p>I also wasn’t convinced that the free tier would have covered the hosting needs of this project. It probably would have been fine — but I would have found myself keeping an eye on bandwidth and API requests and the longterm status of the content.</p>
<p>With the first paid tier starting at $249 per month, levelling up was too expensive to consider. That pricing deterred me from even wanting to use a free account, because I knew I would never upgrade at that price. So there was a chance I’d need to migrate everything if I started building the project on the service.</p>
<p>It was clear Contentful didn’t really want the business of small-scale experimental work — fair enough — and anyway it was getting too annoying to be fussing over these details for a little project.</p>
<h3 id="heading-option-3-restful-wordpress">Option 3: RESTful WordPress</h3>
<p>While I was trying to make Contentful work, I kept switching back to a WordPress install to play around. Bulky though the old WP can be, faced with Contentful’s nickle-and-dime approach of charging for content “records,” I was starting to feel very nostalgic for the ease and freedom of adding content in WordPress.</p>
<p>I thought — well, hey — why not use WordPress as a headless CMS with its new REST API feature? This would let me get around the bulk of serving content through PHP, while still allowing me to use WordPress as a CMS, an interface my students know well.</p>
<p>To allow the students to add all the images and audio for their projects, I would need to add a custom post type. To do that I would need to add a plugin. To use the plugin I would need to figure out how to configure it, and then create an appropriate custom post type that would provide in an easy-to-use interface inside the WP system. To do that I would need to rewrite WordPress from the ground up, because bless its heart it is not built to do anything other than look and feel like WordPress. It manages blog posts really, really, really well, and can be muddled into doing some other things sort of but not well. The whiff of the blog post never really fades.</p>
<p>I gave up on all this before even trying to figure out how I would use the REST API in my project. I’m still excited about it, though. It’s probably an amazing option for serving content from larger sites using JS frameworks.</p>
<h3 id="heading-option-4-wordpress-forms-cms-sugar"><strong>Option 4: WordPress + Forms = CMS Sugar</strong></h3>
<p>The solution I finally settled on seemed ridiculously simple and a funny amalgam of all my earlier efforts.</p>
<p>Using Gravity Forms, a WordPress plugin I know my way around from other projects, I built a basic form through which the students could upload all fifteen of their files, and paste in their text components.</p>
<p>I exported the entries as a spreadsheet with links to the uploaded content stored in the WordPress site, and I turned this file into JSON to use just as I would a Google Sheet.</p>
<p>So my students got a clean, familiar, and accessible experience uploading their content, and I will be able to store it long term without hassle in a format my static web app will play nicely with. Problem solved.</p>
<p>Ta da! Why was this solution not more obvious when I began?</p>
<p>For me, one moral of this story is that even in this era of increasingly fancy decoupled and well-rested deployment options, it still helps to know your way around WordPress — that despite getting a bit long in the tooth, its low-cost, and feature-rich ecosystem continues to lower barriers to digital creativity.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to choose the right CMS based on these important features ]]>
                </title>
                <description>
                    <![CDATA[ By Rachael Ray A Content Management System (CMS) is a web-based application. Multiple users with different access levels can operate the data, as well as modify the content of a website/project or an internet application. Important features your CMS... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/important-features-your-cms-should-have-d4664455558e/</link>
                <guid isPermaLink="false">66c357d50cede4e9b1329c94</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ startup ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 11 May 2018 06:34:03 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*dqLo1bS991w4Ot6-_1v5sQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rachael Ray</p>
<p>A Content Management System (CMS) is a web-based application. Multiple users with different access levels can operate the data, as well as modify the content of a website/project or an internet application.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/d7tIaM7eu16cL8gab5YGeI-gHOxRrnWzZb5W" alt="Image" width="700" height="400" loading="lazy">
<em>Important features your CMS should have</em></p>
<p>If you are <a target="_blank" href="https://www.goodfirms.co/directory/cms/top-website-development-companies"><strong>developing a new website</strong></a>, a Content Management System is your best bet as you will have full control of your content and product sales. The biggest advantage is that you can manage your entire internet marketing strategy under one roof.</p>
<p>A CMS allows you to administer and assign diverse levels of permission access to users. When choosing a CMS, you need to keep two things in mind:</p>
<ul>
<li>Figure out your stakeholders</li>
<li>Prioritize their requirements.</li>
</ul>
<p>Now, deciding on a <a target="_blank" href="https://en.wikipedia.org/wiki/Content_management_system"><strong>CMS platform</strong></a> is akin to buying a new smartphone.</p>
<p>Wondering how?</p>
<p>Let me explain.</p>
<h3 id="heading-choosing-the-right-cms-for-you-and-your-team">Choosing the right CMS for you and your team</h3>
<p>When you sit down to buy a new smartphone, the sheer number of options available will boggle your mind. The same is the case with CMS. The number of platforms to choose from is mind-boggling.</p>
<p>On the one hand, there are the popular and well-known platforms like WordPress, Joomla, and Drupal. And on the other hand, there are around 1000–2000 open source Web Content Management Systems which you can choose from.</p>
<p>Every CMS will have its own set of features to offer. Some platforms may offer all the requisite functions you need, while others might offer an unmatched intuitive experience. So, it becomes confusing as to which features are crucial as there are many basic features which are common to all the CMS platforms.</p>
<p>Here are a <strong>few basic features</strong> which you should consider while choosing a CMS platform. They are mostly common across all platforms:</p>
<ul>
<li>The platform should be steadfast and convenient</li>
<li>It should have an easy navigation</li>
<li>The platform should be flexible</li>
<li>The site maintenance cost should not be very high</li>
<li>The platform should have a streamlined authoring process</li>
</ul>
<p>Apart from these basic features, there are three very important features your CMS should have. Let’s take a look at them in more detail:</p>
<h4 id="heading-1-an-open-api"><strong>1) An open API</strong></h4>
<p>API is the most commonly used term when it comes to CMS. Everybody from Mark Zuckerberg to the developer next door talks about APIs. What makes the API such a crucial feature?</p>
<p>An Application Programming Interface (API) is an intermediary software that promotes data exchange between two systems so that they can interact and share data with ease.</p>
<p>A CMS with an open API allows you to create a website and build apps that are detached from their content management tools and are integrated via the API. This gives you the benefit of using your choice of front-end tools. Also, you will be able to integrate a customized CMS with other external and internal systems, effortlessly. It is commercially viable and saves a lot of time, too.</p>
<h4 id="heading-2-out-of-the-box-plugins"><strong>2) Out of the box Plugins</strong></h4>
<p>Plugins allow you to customize attributes of your website effortlessly and easily.</p>
<p>They help in enhancing the scalability and functionality of the website.</p>
<p>Look for a CMS platform which has built-in SEO tools. With these, you can optimize the page for both the readers and the search engine. Having SEO plugins will help you to add page titles, put in metadata descriptions, and will also help in complying with the accessibility guidelines. It will also help in preventing duplicate content.</p>
<p>Also, when deciding on a platform, make sure you choose a platform which offers social media widgets and online marketing tools. This will make it easy for you to add social media sharing buttons to any piece or page of your content.</p>
<p>Plugins also allow you to integrate ERP (Enterprise Resource Planner) and CRM (Customer Relationship Management) systems. Make sure that your chosen platform has such plugins.</p>
<p>WordPress as a CMS platform offers scores of plugins. Also, it is the most preferred platform and there is a huge demand for WordPress website development in the market. To get the best service for your web development needs, you can hire one of the <a target="_blank" href="https://www.goodfirms.co/directory/cms/top-website-development-companies/wordpress"><strong>top WordPress development companies</strong></a>.</p>
<h4 id="heading-3-design-independence"><strong>3) Design independence</strong></h4>
<p>Finally, the platform you choose should be open enough to allow modifications to the design and the layout. A customized design will have a huge impact on the user and thus will make them stay longer on the page. The platform should also offer flexibility to customize the interface so that you can craft the best experience for managing your content. The platform should not impose the templates on you. Rather it should be flexible enough to allow customization.</p>
<p>The CMS platform should provide you with the authority to make changes to the templates so that you can make your content stand out. It also allows you to bring into focus certain aspects on your page which you might want to highlight.</p>
<p>The CMS should give you the freedom to tweak and re-frame a few aspects so that it is in accordance with your needs and requirements.</p>
<p>Also, having a personalized design will encourage the customer to browse through your content and stay on the page rather than flipping through it.</p>
<h3 id="heading-to-sum-up"><strong>To sum up</strong></h3>
<p>Now that you know which features to look out for, you can settle on your desired CMS platform and weed out the rest.</p>
<p>After all, a good Content Management System is a platform which is able to incorporate all your business needs and requirements and minimize the limitations as far as possible.</p>
<p>Be it micro data requirements or easy to use templates, your CMS should have these important features discussed above so that your business can deliver a seamless digital experience to all your customers.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
