Skip to content

Commit

Permalink
Adding Umbraco to "Use a CMS with Astro" guide (withastro#7879)
Browse files Browse the repository at this point in the history
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Co-authored-by: Richard Jackson <richard.jackson@nightingalehq.ai>
Co-authored-by: Reuben Tier <64310361+TheOtterlord@users.noreply.github.com>
  • Loading branch information
4 people authored and wpplumber committed May 15, 2024
1 parent e753d6d commit a4f1f37
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 0 deletions.
10 changes: 10 additions & 0 deletions public/logos/umbraco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
231 changes: 231 additions & 0 deletions src/content/docs/en/guides/cms/umbraco.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
---
title: Umbraco & Astro
description: Add content to your Astro project using Umbraco as a CMS
type: cms
stub: false
service: Umbraco
i18nReady: true
---
import { FileTree, Steps } from '@astrojs/starlight/components';
import ReadMore from '~/components/ReadMore.astro';


[Umbraco CMS](https://umbraco.com/) is an open-source ASP.NET Core CMS. By default, Umbraco uses Razor pages for its front-end, but can be used as a headless CMS.

## Integrating with Astro

In this section you will use Umbraco's native [Content Delivery API](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api) to provide content to your Astro project.

### Prerequisites

To get started, you will need to have the following:

1. **An Astro project** - If you don’t have an Astro project yet, our [Installation guide](https://docs.astro.build/en/install/auto/) will get you up and running in no time.
2. **An Umbraco (v12+) project** - If you don’t have an Umbraco project yet, please see this [Installation guide](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install/).

### Setting up the Content Delivery API

To enable the Content Delivery API, update your Umbraco project's `appsettings.json` file:

```json title="appsettings.json"
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"PublicAccess": true
}
}
}
}
```

You can configure additional options as needed such as public access, API keys, allowed content types, membership authorisation, and more. See the [Umbraco Content Delivery API documentation](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api) for more information.

### Fetching Data

Use a `fetch()` call to the Content Delivery API to access your content and make it available to your Astro components.

The following example displays a list of fetched articles, including properties such as the article date and content.

```astro title="src/pages/index.astro"
---
const res = await fetch('http://localhost/umbraco/delivery/api/v2/content?filter=contentType:article');
const articles = await res.json();
---
<h1>Astro + Umbraco 🚀</h1>
{
articles.items.map((article) => (
<h1>{article.name}</h1>
<p>{article.properties.articleDate}</p>
<div set:html={article.properties.content?.markup}></div>
))
}
```


<ReadMore>Read more about [data fetching in Astro](https://docs.astro.build/en/guides/data-fetching/).</ReadMore>

## Building a blog with Umbraco and Astro

### Prerequisites

- **An Astro project** - If you don’t have an Astro project yet, our [Installation guide](/en/install/auto/) will get you up and running in no time.

- **An Umbraco project (v12+)** with the Content Delivery API enabled - Follow this [Installation guide](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install/) to create a new project.

### Creating blog posts in Umbraco

From the [Umbraco backoffice](https://docs.umbraco.com/umbraco-cms/fundamentals/backoffice), create a Document Type for a simple blog article called 'Article'.

<Steps>
1. Configure your 'Article' Document Type with the following properties:

- Title (DataType: Textstring)
- Article Date (DataType: Date Picker)
- Content (DataType: Richtext Editor)

2. Toggle "Allow as root" to `true` on the 'Article' document type.

3. From the "Content" section in the Umbraco backoffice, [create and publish your first blog post](https://docs.umbraco.com/umbraco-cms/fundamentals/data/defining-content). Repeat the process as many times as you like.

</Steps>

For more information, watch a [video guide on creating Document Types](https://www.youtube.com/watch?v=otRuIkN80qM).

### Displaying a list of blog posts in Astro

Create a `src/layouts/` folder, then add a new file `Layout.astro` with the following code:

```astro title="src/layouts/Layout.astro"
---
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Blog with Astro and Umbraco</title>
</head>
<body>
<main>
<slot />
</main>
</body>
</html>
```

Your project should now contain the following files:

<FileTree>
- src/
- **layouts/**
- **Layout.astro**
- pages/
- index.astro
</FileTree>

To create a list of blog posts, first `fetch` to call the Content Delivery API `content` endpoint and filter by contentType of 'article'. The article objects will include the properties and content set in the CMS. You can then loop through the articles and display a each title with a link to its article.

Replace the default contents of `index.astro` with the following code:

```astro title="src/pages/index.astro"
---
import Layout from '../layouts/Layout.astro';
const res = await fetch('http://localhost/umbraco/delivery/api/v2/content?filter=contentType:article');
const articles = await res.json();
---
<Layout>
<h2>Blog Articles</h2>
{
articles.items.map((article: any) => (
<div>
<h3>{article.properties.title}</h3>
<p>{article.properties.articleDate}</p>
<a href={article.route.path}>Read more</a>
</div>
))
}
</Layout>
```

### Generating individual blog posts

Create the file `[...slug].astro` at the root of the `/pages/` directory. This file will be used to [generate the individual blog pages dynamically](https://docs.astro.build/en/guides/routing/#dynamic-routes).

Note that the `params` property, which generates the URL path of the page, contains `article.route.path` from the API fetch. Similarly, the `props` property must include the entire `article` itself so that you can access all the information in your CMS entry.

Add the following code to `[...slug].astro` which will create your individual blog post pages:

```astro title="[...slug].astro"
---
import Layout from '../layouts/Layout.astro';
export async function getStaticPaths() {
let data = await fetch("http://localhost/umbraco/delivery/api/v2/content?filter=contentType:article");
let articles = await data.json();
return articles.items.map((article: any) => ({
params: { slug: article.route.path },
props: { article: article },
}));
}
const { article } = Astro.props;
---
<Layout>
<h1>{article.properties.title}</h1>
<p>{article.properties.articleDate}</p>
<div set:html={article.properties.content?.markup}></div>
</Layout>
```

Your project should now contain the following files:

<FileTree>
- src/
- layouts/
- Layout.astro
- pages/
- index.astro
- **[...slug].astro**
</FileTree>

With the dev server running, you should now be able to view your Umbraco-created content in your browser preview of your Astro project. Congratulations! 🚀


## Publishing your site

To deploy your site visit our [deployment guides](https://docs.astro.build/en/guides/deploy/) and follow the instructions for your preferred hosting provider.

## Local dev, HTTPS and self-signed SSL certificates

If you are using the Umbraco HTTPS endpoint locally, any `fetch` queries will result in `fetch failed` with code `DEPTH_ZERO_SELF_SIGNED_CERT`. This is because Node (upon which Astro is built) won't accept self-signed certificates by default. To avoid this, use the Umbraco HTTP endpoint for local dev.

Alternatively, you can set `NODE_TLS_REJECT_UNAUTHORIZED=0` in an `env.development` file and update `astro.config.js` as shown:

```sh title=".env.development"
NODE_TLS_REJECT_UNAUTHORIZED=0
```

```astro title="astro.config.mjs"
import { defineConfig } from 'astro/config';
import { loadEnv } from "vite";
const { NODE_TLS_REJECT_UNAUTHORIZED } = loadEnv(process.env.NODE_ENV, process.cwd(), "");
process.env.NODE_TLS_REJECT_UNAUTHORIZED = NODE_TLS_REJECT_UNAUTHORIZED;
// https://astro.build/config
export default defineConfig({});
```

This method is described in more detail in this [blog post showing how to configure your project for self-signed certificates](https://kjac.dev/posts/jamstack-for-free-with-azure-and-cloudflare/), with an [accompanying repo](https://github.com/kjac/UmbracoAzureCloudflare).

## Official Documentation
- [Content Delivery API - Umbraco Documentation](https://docs.umbraco.com/umbraco-cms/reference/content-delivery-api)

## Community Resources

- [Astro-nomically Performant Websites using the Content Delivery API - Louis Richardson](https://24days.in/umbraco-cms/2023/sustainable-performant/astronomically-performant/)
- [Generating a TypeScript OpenAPI client from Umbraco's Content Delivery API - Rick Butterfield](https://rickbutterfield.dev/blog/typescript-openapi-umbraco-content-delivery/)
- [Jamstack For Free With Azure And CloudFlare - Kenn Jacobsen](https://kjac.dev/posts/jamstack-for-free-with-azure-and-cloudflare/)
- [Quick n' dirty blog with Astro and Umbraco - Kenn Jacobsen](https://kjac.dev/posts/quick-n-dirty-blog-with-astro-and-umbraco/)
1 change: 1 addition & 0 deletions src/data/logos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const logos = LogoCheck({
zerops: { file: 'zerops.svg', padding: '.2em' },
apostrophecms: { file: 'apostrophecms.svg', padding: '.15em .15em' },
db: { file: 'db.svg', padding: '.1em' },
umbraco: { file: 'umbraco.svg', padding: '.05em' },
});

export type LogoKey = keyof typeof logos;
Expand Down

0 comments on commit a4f1f37

Please sign in to comment.