We are rendering structured text on our react frontend. We need to push DFP ads within the body content. One ad after first two paragraphs, second ad after first 6 paragraphs and so on. Is it possible to push DFP ads while we are rendering with StructuredText?
You can do something like this, using a forked version of our Next.js marketing starter’s Post page as an example:
import {type StructuredTextDocument} from 'react-datocms'; // Stronger typing from our helper lib
import {PostQuery} from "@/graphql/types/graphql"; // Generated types from this project's graphql-codegen, specifically for this project's Structured Text Schema
/** First we define our custom types */
// Create a new type for our injected node
type DFPNode = { type: 'dfp' }
// We'll extend StructuredTextDocument from react-datocms
interface StructuredTextDocumentWithDFP extends StructuredTextDocument {
document: {
children: (StructuredTextDocument['document']['children'] | DFPNode)[]
} & StructuredTextDocument['document']
}
// We'll also extend the generated type from this project's graphql-typegen
interface PostQueryWithDFP extends PostQuery {
post: {
content: StructuredTextDocumentWithDFP
} & PostQuery['post']
}
/** Then we'll inject the nodes */
const originalStructuredText = data.post.content // Equal to PostQuery.post.content
const originalStructuredTextTopLevelNodes = originalStructuredText.value as StructuredTextDocument // This imported typedef is better than what graphql-typegen gives us
const dfpNode = {type: 'dfp'} as DFPNode; // Our new placeholder node to be injected
// Copying the children into our new type
let newChildren = [...originalStructuredTextTopLevelNodes.document.children] as StructuredTextDocumentWithDFP['document']['children']
// Modify the array in-place
if (newChildren.length >= 2) {
newChildren.splice(2, 0, dfpNode);
for (let i = 7; i < newChildren.length; i += 5) {
newChildren.splice(i, 0, dfpNode);
}
}
// Make a new top-level hierarchy of nodes
const newStructuredTextToplevelNodes = {
...originalStructuredTextTopLevelNodes,
document: {
...originalStructuredTextTopLevelNodes.document,
children: newChildren,
}
} as StructuredTextDocumentWithDFP
// Build a new structured text object with our new type
const newStructuredText = {
...originalStructuredText,
value: newStructuredTextToplevelNodes
} as PostQueryWithDFP['post']['content']
// Define a new render rule
const dfpNodeRule = renderNodeRule(
// @ts-expect-error The node renderer doesn't understand our custom (fake) node type, but that's OK
(node) => node.type === 'dfp',
() => {
return <div style={{
width: '100px',
height: '100px',
background: 'orange',
padding: '10px',
margin: "20px auto",
textAlign: "center",
display: 'flex',
alignItems: 'center',
}}>AD GOES HERE</div>;
}
)
// Add it to the existing list of render rules
const nodeRulesWithDFP = [...originalNodeRules, dfpNodeRule]
Then we use it in the JSX like this:
<StructuredText
data={newStructuredText}
customNodeRules={nodeRulesWithDFP}
// other props here
/>