Remix

How to use PMKIN with Remix

This guide comprehensively integrates PMKIN, a powerful headless CMS, with your Remix application. We'll walk through each process step, from initial setup to rendering content and optimizing for SEO.

Installation and Setup

Start by adding the necessary packages to your Remix project. Open your terminal and run:

npm install @apollo/client graphql react-markdown

These packages will allow you to interact with PMKIN's GraphQL API (@apollo/client and graphql) and render markdown content (react-markdown) in your Remix application.

To securely use PMKIN's API, you must set up your API key as an environment variable. Create a .env file in your project root if it doesn't already exist, and add the following line:

PMKIN_API_KEY=your_api_key_here

Replace your_api_key_here with the actual API key you obtained from your PMKIN dashboard.

Creating the Apollo Client

To interact with PMKIN's GraphQL API, you must set up an Apollo Client instance. Create a new file app/lib/apollo-client.ts and add the following code:

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'

const httpLink = createHttpLink({
  uri: 'https://content.pmkin.io/graphql'
})

const authLink = setContext((_, { headers }) => {
  // Get the API key from the environment variable
  const token = process.env.PMKIN_API_KEY

  // Return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ''
    }
  }
})

export const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

This setup creates an Apollo Client instance that points to PMKIN's GraphQL endpoint, includes your API key in the authorization header of each request, and uses an in-memory cache for efficient data management. You'll use this client to query PMKIN's API throughout your application.

Listing Documents

To fetch and display a list of documents from PMKIN, you'll need to create a GraphQL query and use it in a loader function. Create a new file for your blog list page, e.g., app/routes/blog.tsx, and add the following code:

import { useLoaderData, Link } from '@remix-run/react'
import { json } from '@remix-run/node'
import { gql } from '@apollo/client'

import { client } from '~/lib/apollo-client'

const GET_DOCUMENTS = gql`
  query GetDocuments {
    documents(includeDrafts: false) {
      id
      title
      slug
      metaDescription
    }
  }
`

export const loader = async () => {
  const { data } = await client.query({ query: GET_DOCUMENTS })

  return json({ documents: data.documents })
}

export default function BlogList() {
  const { documents } = useLoaderData<typeof loader>()

  return (
    <div>
      <h1>Blog Posts</h1>
      {documents.map((doc) => (
        <article key={doc.id}>
          <h2><Link to={doc.slug}>{doc.title}</Link></h2>
          <p>{doc.metaDescription}</p>
        </article>
      ))}
    </div>
  )
}

This code defines a GraphQL query to fetch all published documents, uses the query in a loader function to fetch the data server-side, and renders a list of blog posts with links to individual post pages.

Rendering Document Content

PMKIN provides HTML and Markdown versions of your content. You have two options for rendering individual document content.

To use the pre-rendered HTML version of your content, create a new file for individual blog posts, e.g., app/routes/blog.$slug.tsx, and add the following code:

import { useLoaderData } from '@remix-run/react'
import { json, LoaderFunction } from '@remix-run/node'
import { gql } from '@apollo/client'

import { client } from '~/lib/apollo-client'

const GET_DOCUMENT = gql`
  query GetDocument($slug: String!) {
    documentBySlug(slug: $slug) {
      id
      title
      html
    }
  }
`

export const loader: LoaderFunction = async ({ params }) => {
  const { data } = await client.query({
    query: GET_DOCUMENT,
    variables: { slug: params.slug }
  })

  return json({ document: data.documentBySlug })
}

export default function BlogPost() {
  const { document } = useLoaderData<typeof loader>()

  return (
    <article>
      <h1>{document.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: document.html }} />
    </article>
  )
}

This approach uses the pre-rendered HTML from PMKIN, which can be faster but gives you less control over the rendering process.

Alternatively, to render the Markdown version of your content, modify the GraphQL query to fetch the markdown instead of HTML and use ReactMarkdown to render the content:

import ReactMarkdown from 'react-markdown'

const GET_DOCUMENT = gql`
  query GetDocument($slug: String!) {
    documentBySlug(slug: $slug) {
      id
      title
      markdown
    }
  }
`

export default function BlogPost() {
  const { document } = useLoaderData<typeof loader>()

  return (
    <article>
      <h1>{document.title}</h1>
      <ReactMarkdown>{document.markdown}</ReactMarkdown>
    </article>
  )
}

This approach gives you more control over the rendering process and allows you to customize how different elements are displayed.

Adding Meta Tags

To optimize your pages for SEO, you can add dynamic meta tags using Remix's meta export. Modify your GraphQL query to fetch meta information:

const GET_DOCUMENT = gql`
  query GetDocument($slug: String!) {
    documentBySlug(slug: $slug) {
      id
      title
      markdown  # or html, depending on your rendering choice
      metaTitle
      metaDescription
    }
  }
`

Then, add a meta export to your route file:

import type { MetaFunction } from '@remix-run/node'

export const meta: MetaFunction = ({ data }) => {
  return [
    { title: data.document.metaTitle },
    { name: 'description', content: data.document.metaDescription },
    // Add more meta tags as needed
  ]
}

This setup will dynamically set the page title and description based on the data from PMKIN, improving your SEO and social media sharing capabilities.

Now, you are ready to style your components and add additional features specific to your blog or website. You can expand on this basic setup by adding pagination, categories, or search functionality using PMKIN's API.