Skip to content

Commit

Permalink
examples: Add cms-umbraco example (#52777)
Browse files Browse the repository at this point in the history
Co-authored-by: Lee Robinson <me@leerob.io>
  • Loading branch information
kjac and leerob authored Aug 29, 2024
1 parent 21e51cf commit 38d1987
Show file tree
Hide file tree
Showing 50 changed files with 1,363 additions and 0 deletions.
11 changes: 11 additions & 0 deletions examples/cms-umbraco/.env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is necessary when you run locally against a self-signed server. Do NOT include this in production.
NODE_TLS_REJECT_UNAUTHORIZED=0

# Add your Umbraco server URL here. Please do not include a trailing slash.
UMBRACO_SERVER_URL =

# Add your Umbraco Delivery API key here if you want to use preview.
UMBRACO_DELIVERY_API_KEY =

# Add the secret token that will be used to "authorize" preview
UMBRACO_PREVIEW_SECRET =
35 changes: 35 additions & 0 deletions examples/cms-umbraco/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
161 changes: 161 additions & 0 deletions examples/cms-umbraco/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# A statically generated blog example using Next.js and Umbraco CMS

This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [Umbraco CMS](https://www.umbraco.com/) as the data source.

## Demo

### https://nextjs-umbraco-sample-blog.vercel.app/

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example cms-umbraco umbraco-app
# or
yarn create next-app --example cms-umbraco umbraco-app
# or
pnpm create next-app --example cms-umbraco umbraco-app
```

## Configuration

### Step 1. Create an Umbraco project

Use the .NET CLI to create a project locally.

1. Create an empty folder and open a terminal there.
2. If you haven't already, install the Umbraco .NET CLI templates for version 12.0 or above by running: `dotnet new install Umbraco.Templates::13.*`.
3. Create the Umbraco project by running: `dotnet new umbraco`

For more information on the Umbraco .NET CLI templates, visit [this page](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install/install-umbraco-with-templates).

### Step 2. Install sample data

To avoid having to create the entire blog dataset in hand, we have created a [NuGet package](https://www.nuget.org/packages/Umbraco.Sample.Headless.Blog) with everything you need to get started.

Install the NuGet package with the following command in the terminal window: `dotnet add package Umbraco.Sample.Headless.Blog`.

### Step 3. Configure the Umbraco Delivery API

The Umbraco Delivery API will be the data source for the blog. This API must be enabled explicitly.

Open `appsettings.json` and add the `DeliveryApi` configuration inside `Umbraco::CMS`:

```json
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"ApiKey": "my-secret-api-key"
},
....
```

_The `ApiKey` configuration is optional, though necessary if you want to use the preview functionality of the blog sample._

### Step 4. Run Umbraco

Start Umbraco with the following command in the terminal window: `dotnet run`.

Follow the installation wizard to complete the Umbraco setup.

Once completed you'll be redirected to the Umbraco backoffice where the blog sample data is already installed.

### Step 5. Publish the sample data

All the sample content is unpublished to begin with. You need to publish all of it to show the blog posts on the blog.

1. Click the _Posts_ item in the Content tree. This item contains all the individual blog posts.
2. In the lower right hand corner of the browser you'll find a green button labelled "Save and publish".
3. Click the little up-arrow next to this button and select "Publish with descendants...".
4. In the dialog, tick "Include unpublished content items" to publish the _Posts_ item and all the blog posts in one go.

Now do the same for the _Authors_ item.

### Step 6. Set up environment variables

Locate `.env.local.example` where you created the `umbraco-app` project. Create a copy of the file and name it `.env.local`. Now edit the file and fill in the blanks.

- `UMBRACO_SERVER_URL`: The base URL of your Umbraco site. Avoid trailing slashes here.
- `UMBRACO_DELIVERY_API_KEY`: The API key you configured in `appsettings.json`. This is only necessary if you want to test Preview Mode.
- `UMBRACO_PREVIEW_SECRET` This can be any random string (but avoid spaces), like `my-preview-secret`. This is used for triggering preview, thus only necessary if you want to test Preview Mode.

The file should end up looking something like this:

```
NODE_TLS_REJECT_UNAUTHORIZED=0
UMBRACO_SERVER_URL = 'https://localhost:12345'
UMBRACO_DELIVERY_API_KEY = 'my-secret-api-key'
UMBRACO_PREVIEW_SECRET = 'my-preview-secret'
```

Notice the `NODE_TLS_REJECT_UNAUTHORIZED=0` setting. When running a .NET website locally, a self-signed SSL certificate is created to allow HTTPS bindings. Node.js does not trust self-signed SSL certificates, so you need to bypass the SSL/TLS certificate verification with this setting. Do not use this workaround in production.

### Step 7. Run Next.js in development mode

In the `umbraco-app` project folder, run:

```bash
npm install
npm run dev

# or

yarn install
yarn dev
```

Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/vercel/next.js/discussions).

### Step 8. Try Preview Mode

If you edit a post in Umbraco without publishing the changes, you won't see these changes at `http://localhost:3000` by default. However, if you enable **Preview Mode**, you'll be able to see the changes ([Documentation](https://nextjs.org/docs/advanced-features/preview-mode)).

To enable Preview Mode, go to this URL:

```
http://localhost:3000/api/preview?secret=<secret>
```

- `<secret>` should be the string you entered for `UMBRACO_PREVIEW_SECRET` in `.env.local`.

If you browse to the changed post, you will now see the unpublished changes.

To exit Preview Mode go to this URL:

```
http://localhost:3000/api/exit-preview
```

### Step 9. Deploy on Vercel

You can deploy this app to the cloud with [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).

#### Deploy Umbraco

Before you can deploy the blog to Vercel, you first need to deploy your Umbraco site to a hosting provider, to make the blog data available for Vercel.

If you use Azure, be sure to read [the guidelines](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/server-setup/azure-web-apps) on deploying Umbraco to Azure.

You can also try this out on [Umbraco Cloud](https://umbraco.com/try-umbraco-cms/).

#### Deploy Your Local Project

To deploy your local project to Vercel, push it to GitHub/GitLab/Bitbucket and [import to Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example).

**Important**: When you import your project on Vercel, make sure to click on **Environment Variables** and set them to match your Umbraco deployment.

#### Deploy from Our Template

Alternatively, you can deploy using our template by clicking on the Deploy button below.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco&project-name=nextjs-umbraco-blog&repository-name=nextjs-umbraco-blog&env=UMBRACO_SERVER_URL,UMBRACO_DELIVERY_API_KEY,UMBRACO_PREVIEW_SECRET&envDescription=Required%20to%20connect%20the%20app%20with%20Umbraco%20CMS&envLink=https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco%23step-6-set-up-environment-variables)

### Getting to know Umbraco's Content Delivery API

This example utilizes the native Content Delivery API in Umbraco to fetch the blog data headlessly.

The Content Delivery API is a feature-rich API for headless content delivery. However, in an effort to keep the complexity down in this sample, certain features and optimizations have been omitted from the API queries. This results in slight over-fetching, particularly when fetching multiple blog posts.

You can read all about the Content Delivery API [here](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api).
46 changes: 46 additions & 0 deletions examples/cms-umbraco/components/alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Container from "./container";
import cn from "classnames";
import { EXAMPLE_PATH } from "../lib/constants";

type Props = {
preview?: boolean;
};

export default function Alert({ preview }: Props) {
return (
<div
className={cn("border-b", {
"bg-accent-7 border-accent-7 text-white": preview,
"bg-accent-1 border-accent-2": !preview,
})}
>
<Container>
<div className="py-2 text-center text-sm">
{preview ? (
<>
This is a page preview.{" "}
<a
href="/api/exit-preview"
className="underline hover:text-cyan duration-200 transition-colors"
>
Click here
</a>{" "}
to exit preview mode.
</>
) : (
<>
The source code for this blog is{" "}
<a
href={`https://github.com/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="underline hover:text-success duration-200 transition-colors"
>
available on GitHub
</a>
.
</>
)}
</div>
</Container>
</div>
);
}
24 changes: 24 additions & 0 deletions examples/cms-umbraco/components/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Image from "next/image";
import Author from "../types/author";

type Props = {
author: Author;
};

export default function Avatar({ author }: Props) {
const name: string = author?.name;

return (
<div className="flex items-center">
<div className="w-12 h-12 relative mr-4">
<Image
src={author.picture.url}
layout="fill"
className="rounded-full"
alt={name}
/>
</div>
<div className="text-xl font-bold">{name}</div>
</div>
);
}
7 changes: 7 additions & 0 deletions examples/cms-umbraco/components/container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type Props = {
children: React.ReactNode;
};

export default function Container({ children }: Props) {
return <div className="container mx-auto px-5">{children}</div>;
}
35 changes: 35 additions & 0 deletions examples/cms-umbraco/components/cover-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import cn from "classnames";
import Image from "next/image";
import Link from "next/link";
import Picture from "../types/picture";

type Props = {
title: string;
coverImage: Picture;
slug?: string;
};

export default function CoverImage({ title, coverImage, slug }: Props) {
const image = (
<Image
width={2000}
height={1000}
alt={`Cover Image for ${title}`}
src={coverImage.url}
className={cn("shadow-small", {
"hover:shadow-medium transition-shadow duration-200": slug,
})}
/>
);
return (
<div className="sm:mx-0">
{slug ? (
<Link href={`/posts${slug}`} aria-label={title}>
{image}
</Link>
) : (
image
)}
</div>
);
}
10 changes: 10 additions & 0 deletions examples/cms-umbraco/components/date.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { parseISO, format } from "date-fns";

type Props = {
dateString: string;
};

export default function Date({ dateString }: Props) {
const date = parseISO(dateString);
return <time dateTime={dateString}>{format(date, "LLLL d, yyyy")}</time>;
}
30 changes: 30 additions & 0 deletions examples/cms-umbraco/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Container from "./container";
import { EXAMPLE_PATH } from "../lib/constants";

export default function Footer() {
return (
<footer className="bg-accent-1 border-t border-accent-2">
<Container>
<div className="py-28 flex flex-col lg:flex-row items-center">
<h3 className="text-4xl lg:text-5xl font-bold tracking-tighter leading-tight text-center lg:text-left mb-10 lg:mb-0 lg:pr-4 lg:w-1/2">
Statically Generated with Next.js.
</h3>
<div className="flex flex-col lg:flex-row justify-center items-center lg:pl-4 lg:w-1/2">
<a
href="https://nextjs.org/docs/basic-features/pages"
className="mx-3 bg-black hover:bg-white hover:text-black border border-black text-white font-bold py-3 px-12 lg:px-8 duration-200 transition-colors mb-6 lg:mb-0"
>
Read Documentation
</a>
<a
href={`https://github.com/vercel/next.js/tree/canary/examples/${EXAMPLE_PATH}`}
className="mx-3 font-bold hover:underline"
>
View on GitHub
</a>
</div>
</div>
</Container>
</footer>
);
}
12 changes: 12 additions & 0 deletions examples/cms-umbraco/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Link from "next/link";

export default function Header() {
return (
<h2 className="text-2xl md:text-4xl font-bold tracking-tight md:tracking-tighter leading-tight mb-20 mt-8">
<Link href="/" className="hover:underline">
Blog
</Link>
.
</h2>
);
}
Loading

0 comments on commit 38d1987

Please sign in to comment.