mirror of
https://github.com/gohugoio/hugoDocs.git
synced 2025-09-14 12:04:57 -04:00
Document transform.PortableText
This commit is contained in:
parent
5f632ab32c
commit
dd26ac49f5
219
content/en/functions/transform/PortableText.md
Normal file
219
content/en/functions/transform/PortableText.md
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
---
|
||||||
|
title: transform.PortableText
|
||||||
|
description: Converts Portable Text to Markdown.
|
||||||
|
categories: []
|
||||||
|
keywords: []
|
||||||
|
action:
|
||||||
|
related:
|
||||||
|
- methods/page/RenderString
|
||||||
|
- methods/page/RenderShortcodes
|
||||||
|
returnType: string
|
||||||
|
signatures: [transform.PortableText MAP]
|
||||||
|
---
|
||||||
|
|
||||||
|
{{< new-in "0.145.0" />}}
|
||||||
|
|
||||||
|
[Portable Text](https://www.portabletext.org/) is a JSON structure that can represent rich text content used by the [Sanity](https://www.sanity.io/) CMS. In Hugo, this function is typically used in a [Content Adapter](https://gohugo.io/content-management/content-adapters/) that creates pages from Sanity data.
|
||||||
|
|
||||||
|
## Types supported
|
||||||
|
|
||||||
|
* `block` and `span`
|
||||||
|
* `image`. Note that the image handling is currently very simple; we link to the `asset.url` using `asset.altText` as the image alt text and `asset.title` as the title. For more fine grained control you may want to process the images in a [image render hook](/render-hooks/images/).
|
||||||
|
* `code` (see the [code-input](https://www.sanity.io/plugins/code-input) plugin). Code will be rendered as [fenced code blocks](/contribute/documentation/#fenced-code-blocks) with any filename provided passed on as a markdown attribute.
|
||||||
|
|
||||||
|
{{< note >}}
|
||||||
|
Since the Portable Text gets converted to Markdown before it gets passed to Hugo, rendering of links, headings, images and code blocks can be controlled with [Render Hooks](https://gohugo.io/render-hooks/).
|
||||||
|
{{< /note >}}
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
### Content Adapter
|
||||||
|
|
||||||
|
{{< code file=content/_content.gotmpl >}}
|
||||||
|
{{ $projectID := "mysanityprojectid" }}
|
||||||
|
{{ $useCached := true }}
|
||||||
|
{{ $api := "api" }}
|
||||||
|
{{ if $useCached }}
|
||||||
|
{{/* See https://www.sanity.io/docs/api-cdn */}}
|
||||||
|
{{ $api = "apicdn" }}
|
||||||
|
{{ end }}
|
||||||
|
{{ $url := printf "https://%s.%s.sanity.io/v2021-06-07/data/query/production" $projectID $api }}
|
||||||
|
|
||||||
|
{{/* prettier-ignore-start */ -}}
|
||||||
|
{{ $q := `*[_type == 'post']{
|
||||||
|
title, publishedAt, summary, slug, body[]{
|
||||||
|
...,
|
||||||
|
_type == "image" => {
|
||||||
|
...,
|
||||||
|
asset->{
|
||||||
|
_id,
|
||||||
|
path,
|
||||||
|
url,
|
||||||
|
altText,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
metadata {
|
||||||
|
dimensions {
|
||||||
|
aspectRatio,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}`
|
||||||
|
}}
|
||||||
|
{{/* prettier-ignore-end */ -}}
|
||||||
|
{{ $body := dict "query" $q | jsonify }}
|
||||||
|
{{ $opts := dict "method" "post" "body" $body }}
|
||||||
|
{{ $r := resources.GetRemote $url $opts }}
|
||||||
|
{{ $m := $r | transform.Unmarshal }}
|
||||||
|
{{ $result := $m.result }}
|
||||||
|
{{ range $result }}
|
||||||
|
{{ if not .slug }}
|
||||||
|
{{ continue }}
|
||||||
|
{{ end }}
|
||||||
|
{{ $markdown := transform.PortableText .body }}
|
||||||
|
{{ $content := dict
|
||||||
|
"mediaType" "text/markdown"
|
||||||
|
"value" $markdown
|
||||||
|
}}
|
||||||
|
{{ $params := dict
|
||||||
|
"portabletext" (.body | jsonify (dict "indent" " "))
|
||||||
|
}}
|
||||||
|
{{ $page := dict
|
||||||
|
"content" $content
|
||||||
|
"kind" "page"
|
||||||
|
"path" .slug.current
|
||||||
|
"title" .title
|
||||||
|
"date" (.publishedAt | time )
|
||||||
|
"summary" .summary
|
||||||
|
"params" $params
|
||||||
|
}}
|
||||||
|
{{ $.AddPage $page }}
|
||||||
|
{{ end }}
|
||||||
|
{{< /code >}}
|
||||||
|
|
||||||
|
|
||||||
|
### Sanity setup
|
||||||
|
|
||||||
|
Below outlines a suitable Sanity studio setup for the above example.
|
||||||
|
|
||||||
|
{{< code file=sanity.config.ts >}}
|
||||||
|
import {defineConfig} from 'sanity'
|
||||||
|
import {structureTool} from 'sanity/structure'
|
||||||
|
import {visionTool} from '@sanity/vision'
|
||||||
|
import {schemaTypes} from './schemaTypes'
|
||||||
|
import {media} from 'sanity-plugin-media'
|
||||||
|
import {codeInput} from '@sanity/code-input'
|
||||||
|
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
name: 'default',
|
||||||
|
title: 'my-sanity-project',
|
||||||
|
|
||||||
|
projectId: 'mysanityprojectid',
|
||||||
|
dataset: 'production',
|
||||||
|
|
||||||
|
plugins: [structureTool(), visionTool(), media(),codeInput()],
|
||||||
|
|
||||||
|
schema: {
|
||||||
|
types: schemaTypes,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
{{< /code >}}
|
||||||
|
|
||||||
|
Type/schema definition:
|
||||||
|
|
||||||
|
{{< code file=schemaTypes/postType.ts >}}
|
||||||
|
import {defineField, defineType} from 'sanity'
|
||||||
|
|
||||||
|
export const postType = defineType({
|
||||||
|
name: 'post',
|
||||||
|
title: 'Post',
|
||||||
|
type: 'document',
|
||||||
|
fields: [
|
||||||
|
defineField({
|
||||||
|
name: 'title',
|
||||||
|
type: 'string',
|
||||||
|
validation: (rule) => rule.required(),
|
||||||
|
}),
|
||||||
|
defineField({
|
||||||
|
name: 'summary',
|
||||||
|
type: 'string',
|
||||||
|
validation: (rule) => rule.required(),
|
||||||
|
}),
|
||||||
|
defineField({
|
||||||
|
name: 'slug',
|
||||||
|
type: 'slug',
|
||||||
|
options: {source: 'title'},
|
||||||
|
validation: (rule) => rule.required(),
|
||||||
|
}),
|
||||||
|
defineField({
|
||||||
|
name: 'publishedAt',
|
||||||
|
type: 'datetime',
|
||||||
|
initialValue: () => new Date().toISOString(),
|
||||||
|
validation: (rule) => rule.required(),
|
||||||
|
}),
|
||||||
|
defineField({
|
||||||
|
name: 'body',
|
||||||
|
type: 'array',
|
||||||
|
of: [
|
||||||
|
{
|
||||||
|
type: 'block',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'image'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'code',
|
||||||
|
options: {
|
||||||
|
language: 'css',
|
||||||
|
languageAlternatives: [
|
||||||
|
{title: 'HTML', value: 'html'},
|
||||||
|
{title: 'CSS', value: 'css'},
|
||||||
|
],
|
||||||
|
withFilename: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
{{< /code >}}
|
||||||
|
|
||||||
|
Note that the above requires some additional plugins to be installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i sanity-plugin-media @sanity/code-input
|
||||||
|
```
|
||||||
|
|
||||||
|
{{< code file=schemaTypes/index.ts >}}
|
||||||
|
import {postType} from './postType'
|
||||||
|
|
||||||
|
export const schemaTypes = [postType]
|
||||||
|
{{< /code >}}
|
||||||
|
|
||||||
|
## Server setup
|
||||||
|
|
||||||
|
Unfortunately, Sanity's API does not support [RFC 7234](https://tools.ietf.org/html/rfc7234) and their output changes even if the data has not. The recommended setup is therefore to use their cached `apicdn` endpoint (see above) and then set up a reasonable polling and file cache strategy in your Hugo configuration, e.g:
|
||||||
|
|
||||||
|
{{< code-toggle file=hugo >}}
|
||||||
|
[HTTPCache]
|
||||||
|
[[HTTPCache.polls]]
|
||||||
|
disable = false
|
||||||
|
low = '30s'
|
||||||
|
high = '3m'
|
||||||
|
[HTTPCache.polls.for]
|
||||||
|
includes = ['https://*.*.sanity.io/**']
|
||||||
|
|
||||||
|
[caches.getresource]
|
||||||
|
dir = ':cacheDir/:project'
|
||||||
|
maxAge = "5m"
|
||||||
|
{{< /code-toggle >}}
|
||||||
|
|
||||||
|
The polling above will be used when running the server/watch mode and rebuild when you push new content in Sanity.
|
||||||
|
|
||||||
|
See [Caching in resources.GetRemote](/functions/resources/getremote/#caching) for more fine grained control.
|
Loading…
x
Reference in New Issue
Block a user