PageSourceSearch

https://cromwellcms.com/docs/development/theme-development/

html cromwellcms.com collected 2026-10-04 13:30:48 UTC 133,281 bytes, 65 lines download raw bytes

1<!doctype html>
2<html class="docs-version-current" lang="en" dir="ltr">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width,initial-scale=1">
6<meta name="generator" content="Docusaurus v2.0.0-beta.6">
7<link rel="alternate" type="application/rss+xml" href="/blog/rss.xml" title="Cromwell CMS Blog RSS Feed">
8<link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="Cromwell CMS Blog Atom Feed"><title data-react-helmet="true">Theme development | Cromwell CMS</title><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:url" content="https://cromwellcms.com/docs/development/theme-development"><meta data-react-helmet="true" name="docusaurus_locale" content="en"><meta data-react-helmet="true" name="docusaurus_version" content="current"><meta data-react-helmet="true" name="docusaurus_tag" content="docs-default-current"><meta data-react-helmet="true" property="og:title" content="Theme development | Cromwell CMS"><meta data-react-helmet="true" name="description" content="Cromwell CMS follows principles of headless CMS where API server runs separately from frontend server. So basically you can create any type of frontend and host it wherever you like. But in this scenario, you need to manage and deploy this frontend by yourself."><meta data-react-helmet="true" property="og:description" content="Cromwell CMS follows principles of headless CMS where API server runs separately from frontend server. So basically you can create any type of frontend and host it wherever you like. But in this scenario, you need to manage and deploy this frontend by yourself."><link data-react-helmet="true" rel="shortcut icon" href="/img/icon_small.png"><link data-react-helmet="true" rel="canonical" href="https://cromwellcms.com/docs/development/theme-development"><link data-react-helmet="true" rel="alternate" href="https://cromwellcms.com/docs/development/theme-development" hreflang="en"><link data-react-helmet="true" rel="alternate" href="https://cromwellcms.com/docs/development/theme-development" hreflang="x-default"><link rel="stylesheet" href="/assets/css/styles.adf4fe22.css">
9<link rel="preload" href="/assets/js/runtime~main.a8162b3a.js" as="script">
10<link rel="preload" href="/assets/js/main.78c54909.js" as="script">
11</head>
12<body>
13<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script>
13<div id="__docusaurus">
14<div><a href="#" class="skipToContent_QVmC">Skip to main content</a></div><nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><img src="/img/logo_small_black.svg" alt="Logo" class="themedImage_3EHU themedImage--light_heW6 navbar__logo"><img src="/img/logo_small_white.svg" alt="Logo" class="themedImage_3EHU themedImage--dark_6pZL navbar__logo"><b class="navbar__title">Cromwell CMS</b></a><a class="navbar__item navbar__link" href="/docs/overview/intro">Installation</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/development/theme-development">Development</a><a class="navbar__item navbar__link" href="/blog">Blog</a></div><div class="navbar__items navbar__items--right"><a href="https://github.com/CromwellCMS/Cromwell" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a><div class="react-toggle toggle_pM6S react-toggle--disabled"><div class="react-toggle-track" role="button" tabindex="-1"><div class="react-toggle-track-check"><span class="toggle_5Cll">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_5Cll">🌞</span></div><div class="react-toggle-thumb"></div></div><input type="checkbox" class="react-toggle-screenreader-only" aria-label="Switch between dark and light mode"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div class="main-wrapper docs-wrapper docs-doc-page"><div class="docPage_qWWs"><button class="clean-btn backToTopButton_THz+" type="button"><svg viewBox="0 0 24 24" width="28"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" fill="currentColor"></path></svg></button><aside class="docSidebarContainer_uK7U"><div class="sidebar_Fbmv"><nav class="menu thin-scrollbar menu_f6NZ menuWithAnnouncementBar_3yio"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-category menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">Overview</a></li><li class="theme-doc-sidebar-item-category menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">Features</a></li><li class="theme-doc-sidebar-item-category menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#">Development</a><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/docs/development/theme-development">Theme development</a></li><li class="theme-doc-sidebar-item-link menu__list-item"><a class="menu__link" tabindex="0" href="/docs/development/plugin-development">Plugin development</a></li><li class="theme-doc-sidebar-item-link menu__list-item"><a class="menu__link" tabindex="0" href="/docs/development/module-config">Module configuration</a></li><li class="theme-doc-sidebar-item-link menu__list-item"><a class="menu__link" tabindex="0" href="/docs/development/frontend-dependencies">Frontend Dependencies</a></li><li class="theme-doc-sidebar-item-link menu__list-item"><a class="menu__link" tabindex="0" href="/docs/development/redirects">Redirects / rewrites</a></li></ul></li><li class="theme-doc-sidebar-item-category menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">Core API</a></li><li class="theme-doc-sidebar-item-category menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">Toolkits</a></li></ul></nav></div></aside><main class="docMainContainer_Pt0n"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_+ye-"><div class="docItemContainer_G97A"><article><div class="tocCollapsible_Rhao theme-doc-toc-mobile tocMobile_HuTu"><button type="button" class="clean-btn tocCollapsibleButton_Rimw">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Theme development</h1></header><p>
14Cromwell CMS follows principles of headless CMS where API server runs separately from frontend server. So basically you can create any type of frontend and host it wherever you like. But in this scenario, you need to manage and deploy this frontend by yourself.<br>
15To simply the workflow Cromwell CMS has its theming engine. Users can easily install Themes from the official market right in their Admin panel GUI, make active, delete them, change layout in the Theme Editor as long as Themes follow the guidelines we are going to show.  </p><p>Cromwell CMS Theme is a <strong>Next.js</strong> app. Theme development is basically Next.js development. If you are not familiar with Next.js, <a href="https://nextjs.org/docs/getting-started" target="_blank" rel="noopener noreferrer">you should definitely start with it first</a>.   </p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="create-a-project"></a>Create a project<a class="hash-link" href="#create-a-project" title="Direct link to heading">#</a></h2><p>As in the <a href="/docs/overview/installation#4-cromwell-cli">Installation guide</a>, Cromwell CLI can create a new project template. Use <code>--type theme</code> argument if you want to create Theme or <code>--type plugin</code> for Plugin.  </p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">npx @cromwell/cli create --type theme my-theme-name</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="project-structure"></a>Project structure<a class="hash-link" href="#project-structure" title="Direct link to heading">#</a></h2><ul><li><strong><code>cromwell.config.js</code></strong> - <a href="/docs/development/module-config">Optional config file for your Theme/Plugin.</a>  </li><li><strong><code>src/pages</code></strong> - Directory for Next.js pages. By default, there&#x27;s <code>index.tsx</code> created by CLI. You can rename it to .jsx if you don&#x27;t want to work with TypeScript.</li><li><strong><code>static</code></strong> - Directory for static files (images). Unlike <code>public</code> directory used by Next.js, <code>static</code> should be distributed with your package. After installation by end-user files from <code>static</code> directory will be copied into <code>public</code> directory of the CMS, from where they will be served to the frontend. You can access static files of your Theme through the following pattern: <code>/themes/${packageName}/${pathInStaticDir}</code>.<br>Image example:  <code>&lt;img src=&quot;/themes/@cromwell/theme-store/free_shipping.png&quot; /&gt;</code></li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="compile"></a>Compile<a class="hash-link" href="#compile" title="Direct link to heading">#</a></h2><p>To make your Theme work with the CMS we generate wrappers and meta files. These files help to inject settings from the admin panel (that&#x27;s how theme editor works) and make <a href="/docs/development/frontend-dependencies">
15Frontend dependencies</a> sharable between plugins. With that, you cannot directly use Next.js CLI, but Cromwell CLI has a replacement that works in a similar way and invokes Next.js CLI under the hood.  </p><p>To start Next.js development server with watcher (same as <code>next dev</code>):</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">npx cromwell build -w</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Or via shortcut:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">npx crw b -w</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Open <a href="http://localhost:4256/" target="_blank" rel="noopener noreferrer">http://localhost:4256/</a> to see your website.  </p><p>When your Theme is ready and you want to try it with the CMS in production environment, your need to build it. Same as <code>next build</code> run:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">npx cromwell build</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Now you can go into Admin panel &gt; Themes &gt; click &quot;Set active&quot; on your Theme card. It will change active CMS Theme at <a href="http://localhost:4016/" target="_blank" rel="noopener noreferrer">http://localhost:4016/</a></p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="data-fetching"></a>Data fetching<a class="hash-link" href="#data-fetching" title="Direct link to heading">#</a></h2><p>There are two data fetching methods: via requests to API server and via <a href="https://typeorm.io/" target="_blank" rel="noopener noreferrer">TypeORM</a>.</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="api"></a>API<a class="hash-link" href="#api" title="Direct link to heading">#</a></h3><p>This way is simplest and it allows you to work with GraphQL. Another advantage is that load is distributed between API server and Next.js server.   </p><p>In development you will probably need to see list of all available API methods. For that start the CMS in development mode. In your project root create <code>cmsconfig.json</code> file with the content:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;env&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;dev&quot;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Now start the CMS:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">
15npx cromwell start </span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>For data flow the CMS uses GraphQL. You can see and play with requests in the <a href="https://www.apollographql.com/" target="_blank" rel="noopener noreferrer">Apollo</a> Graph sandbox. Go to <a href="http://localhost:4016/api/graphql" target="_blank" rel="noopener noreferrer">http://localhost:4016/api/graphql</a> and it will suggest you to start one.</p><p>Additionally there is Nest.js REST API designed for other CMS transaction. You can open swagger at <a href="http://localhost:4016/api/api-docs" target="_blank" rel="noopener noreferrer">http://localhost:4016/api/api-docs</a></p><p>To simplify work with API Server, CMS provides API client from <code>@cromwell/core-frontend</code> package. You can use it on client or server.<br>
16For example, you want to render a page with 3 recent posts:  </p><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">src/pages/index.tsx</div><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">TCromwellPage</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">TGetStaticProps</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">TPost</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> getGraphQLClient </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
17</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name maybe-class-name">MyPageProps</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    latestPosts</span><span class="token operator">?</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TPost</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
18</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> </span><span class="token maybe-class-name">MyPage</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TCromwellPage</span><span class="token operator">&lt;</span><span class="token maybe-class-name">MyPageProps</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">props</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token tag punctuation">&lt;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">        </span><span class="token punctuation">{</span><span class="token plain">props</span><span class="token punctuation">.</span><span class="token plain">latestPosts</span><span class="token operator">?.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token plain">post </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag"> </span><span class="token tag attr-name">key</span><span class="token tag script language-javascript script-punctuation punctuation">=</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript">post</span><span class="token tag script language-javascript punctuation">.</span><span class="token tag script language-javascript">id</span><span class="token tag script language-javascript punctuation">}</span><span class="token tag punctuation">&gt;</span><span class="token punctuation">{</span><span class="token plain">post</span><span class="token punctuation">.</span><span class="token plain">title</span><span class="token punctuation">}</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag punctuation">&gt;</span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
19</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> </span><span class="token maybe-class-name">MyPage</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
20</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword">const</span><span class="token plain"> getStaticProps</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TGetStaticProps</span><span class="token operator">&lt;</span><span class="token maybe-class-name">MyPageProps</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">async</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> client </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">getGraphQLClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> posts </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow">await</span><span class="token plain"> client</span><span class="token punctuation">.</span><span class="token function">getFilteredPosts</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        pagedParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            pageSize</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">3</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        filterParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            sorts</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                    key</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;publishDate&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                    sort</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;DESC&#x27;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token punctuation">]</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
21</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        props</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            latestPosts</span><span class="token operator">:</span><span class="token plain"> posts</span><span class="token punctuation">.</span><span class="token plain">elements</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>In the example above <code>getFilteredPosts</code> used a default fragment for us. But if we want to leverage GraphQL we can provide a custom fragment for a Post: </p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O ts"><pre tabindex="0" class="prism-code language-ts codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">
21import</span><span class="token plain"> </span><span class="token imports punctuation">{</span><span class="token imports"> gql </span><span class="token imports punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@apollo/client&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports punctuation">{</span><span class="token imports"> getGraphQLClient </span><span class="token imports punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
22</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> client </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">getGraphQLClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
23</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> posts </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow">await</span><span class="token plain"> client</span><span class="token punctuation">.</span><span class="token method function property-access">getFilteredPosts</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    pagedParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        pageSize</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">3</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    filterParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        sorts</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                key</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;publishDate&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                sort</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;DESC&#x27;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">]</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    customFragment</span><span class="token operator">:</span><span class="token plain"> gql</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        fragment PostListFragment on Post {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            id</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">
23            slug</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            title</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            createDate</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            excerpt</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            author {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                id</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                email</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                fullName</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            tags {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                name</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        }</span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    customFragmentName</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;PostListFragment&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Or we can make a completely custom request:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O ts"><pre tabindex="0" class="prism-code language-ts codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports punctuation">{</span><span class="token imports"> gql </span><span class="token imports punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@apollo/client&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token imports punctuation">{</span><span class="token imports"> getGraphQLClient </span><span class="token imports punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
24</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> client </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">getGraphQLClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
25</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> response </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow">await</span><span class="token plain"> client</span><span class="token punctuation">.</span><span class="token method function property-access">query</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    query</span><span class="token operator">:</span><span class="token plain"> gql</span><span class="token template-string template-punctuation string">`</span><span class="token template-string string"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        query getFilteredPosts($pagedParams: PagedParamsInput, $filterParams: PostFilterInput) {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            getFilteredPosts(pagedParams: $pagedParams, filterParams: $filterParams) {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                pagedMeta {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                    ...PagedMetaFragment</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                elements {</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                    id</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                    isEnabled</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">
25                    slug</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                    title</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                    mainImage</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">                }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">            }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        }</span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        </span><span class="token template-string interpolation interpolation-punctuation punctuation">${</span><span class="token template-string interpolation">client</span><span class="token template-string interpolation punctuation">.</span><span class="token template-string interpolation property-access maybe-class-name">PagedMetaFragment</span><span class="token template-string interpolation interpolation-punctuation punctuation">}</span><span class="token template-string string"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token template-string string">        </span><span class="token template-string template-punctuation string">`</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    variables</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        pagedParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            pageSize</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">3</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        filterParams</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">          sorts</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">              </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                  key</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;publishDate&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                  sort</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;DESC&#x27;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">              </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">          </span><span class="token punctuation">]</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"> </span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
26</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> posts </span><span class="token operator">=</span><span class="token plain"> response</span><span class="token operator">?.</span><span class="token plain">data</span><span class="token operator">?.</span><span class="token plain">getFilteredPosts</span><span class="token operator">?.</span><span class="token plain">elements</span><span class="token punctuation">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>You can notice that some methods of GraphQLClient create or update database records. They all require authentication. To log in on frontend use REST API client:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O ts"><pre tabindex="0" class="prism-code language-ts codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">
26import</span><span class="token plain"> </span><span class="token imports punctuation">{</span><span class="token imports"> getGraphQLClient</span><span class="token imports punctuation">,</span><span class="token imports"> getRestApiClient </span><span class="token imports punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
27</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> user </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow">await</span><span class="token plain"> </span><span class="token function">getRestApiClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">login</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    email</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;email&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    password</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;password&#x27;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
28</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token comment">// If user is an author or administrator you will be able to create a post:</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token function">getGraphQLClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">createPost</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    title</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;title&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">/** ... */</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p><a href="https://cromwellcms.com/docs/api/classes/frontend.CGraphQLClient" target="_blank" rel="noopener noreferrer">See API docs</a> for the full list of methods.<br>
29Also see <a href="https://cromwellcms.com/docs/features/custom-data" target="_blank" rel="noopener noreferrer">custom data</a> about how to retrieve data of custom fields and entities.  </p><p>For Theme authors it&#x27;s recommended to use API clients. If clients are not enough you can extend API server by <a href="/docs/development/plugin-development#backend">making Plugins</a>.<br>
30If it&#x27;s still not what you want and you are building your own app, there is a second option.</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="monolithic-data-fetching"></a>
30Monolithic data fetching<a class="hash-link" href="#monolithic-data-fetching" title="Direct link to heading">#</a></h3><p>This is yet-to-be-improved approach and it is disabled by default. To connect Next.js server to your database, add an option to your <code>cmsconfig.json</code> and restart the CMS </p><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">cmsconfig.json</div><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;monolith&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Now you can use backend tools from <code>@cromwell/core-backend</code> or make any custom query with TypeORM.</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">TCromwellPage</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">TGetStaticProps</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">TPost</span><span class="token punctuation">,</span><span class="token plain"> nodeRequire </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">declare</span><span class="token plain"> </span><span class="token keyword">const</span><span class="token plain"> </span><span class="token function-variable function">__non_webpack_require__</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token builtin">any</span><span class="token punctuation">;</span><span class="token plain"> </span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
31</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">type</span><span class="token plain"> </span><span class="token class-name maybe-class-name">MyPageProps</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    latestPosts</span><span class="token operator">?</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TPost</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
32</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> </span><span class="token maybe-class-name">MyPage</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TCromwellPage</span><span class="token operator">&lt;</span><span class="token maybe-class-name">MyPageProps</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">props</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token tag punctuation">&lt;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">        </span><span class="token punctuation">{</span><span class="token plain">props</span><span class="token punctuation">.</span><span class="token plain">latestPosts</span><span class="token operator">?.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token plain">post </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag"> </span><span class="token tag attr-name">key</span><span class="token tag script language-javascript script-punctuation punctuation">=</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript">post</span><span class="token tag script language-javascript punctuation">.</span><span class="token tag script language-javascript">id</span><span class="token tag script language-javascript punctuation">}</span><span class="token tag punctuation">&gt;</span><span class="token punctuation">{</span><span class="token plain">post</span><span class="token punctuation">.</span><span class="token plain">title</span><span class="token punctuation">}</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag punctuation">&gt;</span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
33</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> </span><span class="token maybe-class-name">MyPage</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
34</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword">const</span><span class="token plain"> getStaticProps</span><span class="token operator">:</span><span class="token plain"> </span><span class="token maybe-class-name">TGetStaticProps</span><span class="token operator">&lt;</span><span class="token maybe-class-name">MyPageProps</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword">async</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain">context</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">// We use __non_webpack_require__ to avoid processing heavy modules by Webpack</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">// since they will be present in user backend environment anyway.</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> getCustomRepository</span><span class="token punctuation">,</span><span class="token plain"> getManager </span><span class="token punctuation">}</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword">typeof</span><span class="token plain"> </span><span class="token keyword module">
34import</span><span class="token punctuation">(</span><span class="token string">&#x27;typeorm&#x27;</span><span class="token punctuation">)</span><span class="token plain"> </span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">__non_webpack_require__</span><span class="token punctuation">(</span><span class="token string">&#x27;typeorm&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
35</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">PostRepository</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">Post</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token operator">:</span><span class="token plain"> </span><span class="token keyword">typeof</span><span class="token plain"> </span><span class="token keyword module">import</span><span class="token punctuation">(</span><span class="token string">&#x27;@cromwell/core-backend&#x27;</span><span class="token punctuation">)</span><span class="token plain"> </span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function">__non_webpack_require__</span><span class="token punctuation">(</span><span class="token string">&#x27;@cromwell/core-backend&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
36</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">// Use repository methods</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword">const</span><span class="token plain"> posts </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword control-flow">await</span><span class="token plain"> </span><span class="token function">getCustomRepository</span><span class="token punctuation">(</span><span class="token maybe-class-name">PostRepository</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getFilteredPosts</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        pageSize</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">3</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        sorts</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                key</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;publishDate&#x27;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">                sort</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&#x27;DESC&#x27;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">]</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
37</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">// Use query builder</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token function">getManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createQueryBuilder</span><span class="token punctuation">(</span><span class="token maybe-class-name">Post</span><span class="token punctuation">.</span><span class="token plain">metadata</span><span class="token punctuation">.</span><span class="token plain">tablePath</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">select</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">&#x27;id&#x27;</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
38</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token comment">// Execute raw SQL</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token function">getManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token string">&#x27;SELECT * FROM crw_post&#x27;</span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
39</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        props</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">            latestPosts</span><span class="token operator">:</span><span class="token plain"> posts</span><span class="token punctuation">.</span><span class="token plain">elements</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">        </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p><a href="https://cromwellcms.com/docs/api/modules/backend" target="_blank" rel="noopener noreferrer">See API docs</a> for all available backend classes and functions.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="theme-editor-support"></a>
39Theme Editor support<a class="hash-link" href="#theme-editor-support" title="Direct link to heading">#</a></h2><p>Admin panel Theme Editor allows users to modify layout of blocks, change text or images, styles, etc. This feature works only with standard <code>Blocks</code> - React components designed for a single purpose: Image Block, Text Block, etc.<br>
40It doesn&#x27;t impose any restrictions on how you build your Theme. You still can write any JSX code, but if you want, for example, some image to be modifiable in the Theme Editor, you need to use Image Block.  </p><p>Let&#x27;s look into example:</p><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">src/pages/index.tsx</div><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">TCromwellPage</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">CContainer</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token constant">CHTML</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">CImage</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token maybe-class-name">CText</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">import</span><span class="token plain"> </span><span class="token maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;react&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
41</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword">const</span><span class="token plain"> </span><span class="token maybe-class-name">HomePage</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function-variable function maybe-class-name">TCromwellPage</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CContainer</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">home_0</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CText</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">home_1</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text">
41`User can edit this text`</span><span class="token tag punctuation">&lt;/</span><span class="token tag class-name">CText</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CImage</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">home_2</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">/themes/you-theme-name/modifiable-image.jpg</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CHTML</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">home_3</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">      </span><span class="token tag punctuation">&lt;</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">        </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text">
41`User can edit this text and all HTML tags inside CHTML Block`</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">      </span><span class="token tag punctuation">&lt;/</span><span class="token tag">div</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag class-name">CHTML</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CContainer</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">home_4</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">      </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text">`User will NOT be able to edit this text, but he can drag or delete`</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">      </span><span class="token tag punctuation">&lt;</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text">`this CContainer with everything inside it`</span><span class="token tag punctuation">&lt;/</span><span class="token tag">p</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">      </span><span class="token tag punctuation">&lt;</span><span class="token tag">img</span><span class="token tag"> </span><span class="token tag attr-name">src</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">/themes/you-theme-name/non-modifiable-image.jpg</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">    </span><span class="token tag punctuation">&lt;/</span><span class="token tag class-name">CContainer</span><span class="token tag punctuation">&gt;</span><span class="token plain-text"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain-text">  </span><span class="token tag punctuation">&lt;/</span><span class="token tag class-name">CContainer</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
42</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> </span><span class="token maybe-class-name">HomePage</span><span class="token punctuation">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>We put elements into <code>CContainer</code>s. This component equals to <code>&lt;div&gt;</code> tag plus properties available to all Blocks: </p><ul><li>Draggable - User can drag and drop Block into another position inside any other CContainer.</li><li>Modifiable - User can edit properties of Block. Properties can be common such as styles and Block type-specific such as &#x27;image path&#x27; for <code>CImage</code> Block. </li><li>Removable - User can delete Block. Component will remain in the code since we cannot edit files of your Theme, but it will render nothing instead of its content.</li></ul><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewB
42ox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>important</h5></div><div class="admonition-content"><p>You must always provide a unique <code>id</code> prop to Blocks. We need it to keep in sync user&#x27;s and Theme author&#x27;s changes.<br>
43For example, user has modified some Block and then author made a new release where he modified the same Block as well. After Theme update we&#x27;ll have to match differences and override author&#x27;s modifications by user&#x27;s.  </p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="configure-pages"></a>Configure pages<a class="hash-link" href="#configure-pages" title="Direct link to heading">#</a></h2><p>You can apply some custom configurations to your pages in <code>cromwell.config.js</code>. The config has <code>pages</code> property which is array of page configs. CLI template has already added there home page config.  </p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="page-config-properties"></a>Page config properties:<a class="hash-link" href="#page-config-properties" title="Direct link to heading">#</a></h3><ul><li><strong><code>id</code></strong> - Unique id of the page. Required. We need it to recognize pages, since <code>route</code> can possibly be changed for <a href="#generic-pages">Generic pages</a>.</li><li><strong><code>route</code></strong> - Page&#x27;s route. Required. Usually it has the same value as in Next.js file-routing. For example, if you have created file: <code>info/contacts.tsx</code>, then your page will be served at <code>info/contacts</code> by Next.js, so <code>route</code> value will be <code>info/contacts</code>. If your page is dynamic, for example <code>product/[slug].tsx</code>, then value is <code>product/[slug]</code>. There&#x27;s one exception with the Home page, we use <code>index</code> value for it.</li><li><strong><code>name</code></strong> - Name of the page displayed in Theme Editor sidebar.</li><li><strong><code>title</code></strong> - Meta title (SEO). Cromwell CMS will automatically import Head component from <code>next/head</code> package for the title to work in the frontend. But you also can use <code>next/head</code> in your code. Note that <code>title</code> from the page config overrides title in your React component.</li><li><strong><code>description</code></strong> - Meta description (SEO).</li><li><strong><code>headHtml</code></strong> - Custom HTML injected in the head. After Pre-build phase your pages will be wrapped by our root component to make these injections. </li><li><strong><code>footerHtml</code></strong> - Custom HTML injected at the end of the page.</li><li><strong><code>modifications</code></strong> - Modifications of Blocks. Part of Theme Editor system. All custom modifications for Blocks (such as dragging, styling) are stored as JSON configs in <code>modifications</code>. There are two types of them: author&#x27;s and user&#x27;s. Author&#x27;s modifications stored in <code>cromwell.config.js</code> under this property. User&#x27;s modifications are stored in database.<br>In actual usage your modification from the config will be merged and overwritten by user&#x27;s modification from DB.
44When you are making a Theme you can copy modifications from DB into this property.
45It makes it possible to create a Theme using Theme Editor (which is not recommended since Theme Editor doesn&#x27;t have yet advanced features to make a responsive layout) and it would be fully customizable by user.<br><code>modifications</code> property is a flat array of objects (modifications). <a href="https://github.com/CromwellCMS/Cromwell/blob/master/system/core/common/src/types/blocks.ts#L81" target="_blank" rel="noopener noreferrer">See TCromwellBlockData for details</a>. Main properties: <ul><li><strong>id</strong><code>: string</code> - Block id, unique on the page</li><li><strong>type</strong><code>: string</code> - Block type, one of following: &#x27;container&#x27;, &#x27;plugin&#x27;, &#x27;text&#x27;, &#x27;HTML&#x27;, &#x27;image&#x27;, &#x27;gallery&#x27;, &#x27;list&#x27;, &#x27;link&#x27;  </li><li><strong>isVirtual</strong><code>: boolean</code> - If true, indicates that this Block was created in Theme Editor and it doesn&#x27;t exist in source files as React component. Exists only in page&#x27;s config. </li><li><strong>
45parentId</strong><code>: string</code> - Id of a parent container Block.</li><li><strong>index</strong><code>: number</code> - Desirable index (order) inside children array of parent element </li><li><strong>style</strong><code>: React.CSSProperties</code> - CSS styles to apply to this block&#x27;s wrapper. In a format of React CSS properties</li><li><strong>isDeleted</strong><code>: boolean</code> - Non-virtual blocks that exist in JSX cannot physically be deleted in Theme&#x27;s source code by user, but user can set isDeleted flag that will tell this Block to render nothing instead of original content.</li><li><strong>global</strong><code>: boolean</code> - Apply this modification on all pages.</li></ul></li></ul><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</h5></div><div class="admonition-content"><p>It is not necessary to add configs for your pages, and you can start development even without <code>cromwell.config.js</code> file, but if you want your page to work in Admin panel Theme Editor, you have to add a page config for it with at least <code>id</code> and <code>route</code> properties.</p></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="default-pages"></a>Default pages<a class="hash-link" href="#default-pages" title="Direct link to heading">#</a></h3><p><code>cromwell.config.js</code> has <code>defaultPages</code> property that tells Admin panel where to find your pages. For example, in a product page of Admin panel at the top-right menu you can see icon with the tooltip &quot;open product page in the new tab&quot;. The icon opens the same product in frontend page of an active Theme. Since it&#x27;s possible for Theme author to place the product page under any route, you need to specify its route in the <code>defaultPages</code> for Admin panel links to work.  </p><p>All available Default pages with route examples:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;category&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;category/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;product&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;product/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;post&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;post/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;tag&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;tag/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;pages&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;pages/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;account&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;account&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;checkout&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;checkout&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="use-plugins"></a>
45Use Plugins<a class="hash-link" href="#use-plugins" title="Direct link to heading">#</a></h2><p>You will learn about plugins in the <a href="/docs/development/plugin-development">next tutorial</a>.<br>
46As theme authors we are interested about plugin&#x27;s frontend part which is basically a React component. A plain usage will be importing <code>CPlugin</code> component and specifying package name. If a plugin supports settings we also can pass them via props:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">CPlugin</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token comment">/* ... */</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CPlugin</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">main_menu</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag">  </span><span class="token tag attr-name">pluginName</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">@cromwell/plugin-main-menu</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag">  </span><span class="token tag attr-name">plugin</span><span class="token tag script language-javascript script-punctuation punctuation">=</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">    instanceSettings</span><span class="token tag script language-javascript operator">:</span><span class="token tag script language-javascript"> </span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">      mobile</span><span class="token tag script language-javascript operator">:</span><span class="token tag script language-javascript"> </span><span class="token tag script language-javascript boolean">true</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">    </span><span class="token tag script language-javascript punctuation">}</span><span class="token tag script language-javascript punctuation">,</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript"></span><span class="token tag script language-javascript punctuation">}</span><span class="token tag script language-javascript punctuation">}</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Note that some plugins may depend on server-side data fetching. In order to perform it, a plugin should be registered. There are two methods:</p><ol><li>Via <code>registerPluginSSR</code></li></ol><p>Call <code>registerPluginSSR</code> in global context (not inside yor component).</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">
46import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> registerPluginSSR </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
47</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token function">registerPluginSSR</span><span class="token punctuation">(</span><span class="token string">&#x27;@cromwell/plugin-main-menu&#x27;</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">&#x27;*&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
48</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function maybe-class-name">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CPlugin</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">main_menu</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag">      </span><span class="token tag attr-name">plugin</span><span class="token tag script language-javascript script-punctuation punctuation">=</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">        pluginName</span><span class="token tag script language-javascript operator">:</span><span class="token tag script language-javascript"> </span><span class="token tag script language-javascript string">&quot;@cromwell/plugin-main-menu&quot;</span><span class="token tag script language-javascript punctuation">,</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">        instanceSettings</span><span class="token tag script language-javascript operator">:</span><span class="token tag script language-javascript"> </span><span class="token tag script language-javascript punctuation">{</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">          mobile</span><span class="token tag script language-javascript operator">:</span><span class="token tag script language-javascript"> </span><span class="token tag script language-javascript boolean">true</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">        </span><span class="token tag script language-javascript punctuation">}</span><span class="token tag script language-javascript punctuation">,</span><span class="token tag script language-javascript"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token tag script language-javascript">      </span><span class="token tag script language-javascript punctuation">}</span><span class="token tag script language-javascript punctuation">}</span><span class="token tag"> </span><span class="token tag punctuation">/&gt;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>First argument is package name, second is page route (<a href="https://cromwellcms.com/docs/development/theme-development#page-config-properties" target="_blank" rel="noopener noreferrer">see <code>route</code></a>.). Use <code>*</code> to register on all pages.</p><ol start="2"><li>In <code>cromwell.config.js</code></li></ol><p>For example, on your page you can add only container:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O tsx"><pre tabindex="0" class="prism-code language-tsx codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token keyword module">
48import</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"> </span><span class="token maybe-class-name">CContainer</span><span class="token plain"> </span><span class="token punctuation">}</span><span class="token plain"> </span><span class="token keyword module">from</span><span class="token plain"> </span><span class="token string">&#x27;@cromwell/core-frontend&#x27;</span><span class="token punctuation">;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain" style="display:inline-block">
49</span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token keyword module">export</span><span class="token plain"> </span><span class="token keyword module">default</span><span class="token plain"> </span><span class="token keyword">function</span><span class="token plain"> </span><span class="token function maybe-class-name">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token keyword control-flow">return</span><span class="token plain"> </span><span class="token punctuation">(</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token tag punctuation">&lt;</span><span class="token tag class-name">CContainer</span><span class="token tag"> </span><span class="token tag attr-name">id</span><span class="token tag attr-value punctuation attr-equals">=</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag attr-value">menu-container</span><span class="token tag attr-value punctuation">&quot;</span><span class="token tag punctuation">&gt;</span><span class="token tag punctuation">&lt;/</span><span class="token tag class-name">CContainer</span><span class="token tag punctuation">&gt;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token punctuation">)</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>And add Plugin to the <code>modifications</code> of a <a href="#page-config-properties">page config</a>:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;type&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;plugin&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;id&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;main_menu&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;parentId&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;menu-container&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;isVirtual&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;plugin&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token property">&quot;pluginName&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;@cromwell/plugin-main-menu&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token property">&quot;instanceSettings&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token property">&quot;mobile&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="ship-theme-with-plugins"></a>
49Ship Theme with Plugins<a class="hash-link" href="#ship-theme-with-plugins" title="Direct link to heading">#</a></h3><p>You Theme can depend on many plugins, and as in any npm package you can include
50plugins as <code>dependencies</code> in <code>package.json</code>. That will make install and activate plugins along with your Theme. They also will be available to see in the admin panel.<br>
51But one important thing to note is that when you specify plugins in <code>dependencies</code>, user will be unable
52to uninstall plugins in the admin panel and keep your theme. If you want to make them separable then:</p><ol><li>Move Plugin into <code>devDependencies</code> or <code>peerDependencies</code> that way it won&#x27;t be installed automatically
53by package manager in production (when user installs it in the admin panel).</li><li>In your package.json create property <code>cromwell.plugins</code> and list your plugins:  </li></ol><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">package.json</div><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token comment">/* ... */</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token property">&quot;cromwell&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token property">&quot;type&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;theme&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token property">&quot;plugins&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token string">&quot;package-1&quot;</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token string">&quot;package-2&quot;</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>When user installs your theme from admin panel, after running <code>yarn add your-theme-name</code> the CMS will also run <code>yarn add</code> for each listed plugin.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="generic-pages"></a>Generic pages<a class="hash-link" href="#generic-pages" title="Direct link to heading">#</a></h2><p>Users can create a new page in the Theme Editor. Since there&#x27;s no way to add Next.js pages at runtime, this feature is achieved via adding a dynamic page at <code>pages/[slug]</code> route. If your Theme doesn&#x27;t export component at <code>src/pages/pages/[slug].(jsx|tsx)</code>, then it will be generated internally at pre-build phase, but you&#x27;re encouraged to create it yourself since probably you want to have it the same layout as in other pages.  </p><p>Theme authors also can create a generic page in the Theme config. Just add a page config with the route: <code>pages/your-page-name</code> and put modifications to display some content.  </p><p>The difference between generic pages and other pages is that they can have a different page config for a specified slug, while, for example, <code>/product/[slug]</code> page will have the same config for every provided slug.</p><p><a href="/docs/development/redirects/">Use rewrites</a> if you want some generic page appear under your custom route (not under <code>/pages/</code>)</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="multiple-generic-layouts"></a>
53Multiple generic layouts<a class="hash-link" href="#multiple-generic-layouts" title="Direct link to heading">#</a></h3><p>Theme can define multiple layouts (Next.js pages) to use for generic pages. With that user will be able to pick needed layout in the admin panel.</p><p>For example, you created two layouts: <code>pages-old/[slug]</code> and <code>pages-new/[slug]</code>. Now you need to define your generic pages in the config under <code>genericPages</code> property:</p><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">cromwell.config.js</div><div class="codeBlockContent_6g8O js"><pre tabindex="0" class="prism-code language-js codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">module</span><span class="token punctuation">.</span><span class="token property-access">exports</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token comment">/* ... */</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token literal-property property">genericPages</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token literal-property property">route</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;pages-old/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token literal-property property">name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;default&quot;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">{</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token literal-property property">route</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;pages-new/[slug]&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">      </span><span class="token literal-property property">name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string">&quot;pages new&quot;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">    </span><span class="token punctuation">}</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Note that it will override default route for generic pages at <code>pages/[slug]</code>.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="publish"></a>
53Publish<a class="hash-link" href="#publish" title="Direct link to heading">#</a></h2><p>Any Theme or Plugin is an NPM package. That&#x27;s how Cromwell CMS recognizes and manages them. If you want to share your Theme/Plugin you need to publish it as NPM package.</p><p>First configure info that will be displayed in Admin panel. Open <code>package.json</code> &gt; <code>cromwell</code> property &gt; modify fields: <code>title</code>, <code>image</code>, <code>excerpt</code>, <code>description</code>, <code>author</code>. <a href="/docs/development/module-config">More about <code>package.json</code> config</a>  </p><p>Check that all needed directories are included in your npm package. They should be set as &quot;files&quot; in your package.json:</p><div class="codeBlockContainer_8r9j"><div style="color:#d4d4d4;background-color:#1e1e1e" class="codeBlockTitle_j2Dn">package.json</div><div class="codeBlockContent_6g8O json"><pre tabindex="0" class="prism-code language-json codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token property">&quot;files&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation">[</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token string">&quot;build&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token string">&quot;static&quot;</span><span class="token punctuation">,</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain">  </span><span class="token string">&quot;cromwell.config.js&quot;</span><span class="token plain"></span></span><span class="token-line" style="color:#d4d4d4"><span class="token plain"></span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token plain"> </span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Do not include <code>.cromwell</code> and <code>public</code> directories, these are CMS runtime directories.   </p><p>Make sure you have successfully built your Theme/Plugin.<br>
54For a Theme <code>./build</code> directory should contain <code>.next</code>.<br>
55For a Plugin <code>./build</code> directory should reflect <code>src</code> 3 main directories.
56Your Theme/Plugin also should work locally at http://localhost:4016/</p><p>Publish your package to the npm registry:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token function">npm</span><span class="token plain"> publish --access public</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="publish-in-the-cromwell-cms-market"></a>Publish in the Cromwell CMS market<a class="hash-link" href="#publish-in-the-cromwell-cms-market" title="Direct link to heading">#</a></h3><p>For your Theme/Plugin to appear in the Admin panel market at <code>/admin/theme-market</code> page, we need to add it in our central database. For now there&#x27;s no automatic process and all new Modules are checked manually (to ensure build correctness and acceptable code quality). You can reach us for publication at <code><a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d4b7a6bbb9a3b1b8b8b7b9a794b3b9b5bdb8fab7bbb9">[email&#160;protected]</a></code>.<br>
57The publication is free.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_XX5z" id="install"></a>
57Install<a class="hash-link" href="#install" title="Direct link to heading">#</a></h2><p>You can install your Theme/Plugin from the CMS market in the GUI of Admin panel or from npm registry in the terminal.</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_XX5z" id="install-from-npm-registry"></a>Install from npm registry<a class="hash-link" href="#install-from-npm-registry" title="Direct link to heading">#</a></h3><p>Install in existing/running project, or create a new basic project:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token plain">npx @cromwell/cli create my-website</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>Install your Theme:</p><div class="codeBlockContainer_8r9j"><div class="codeBlockContent_6g8O bash"><pre tabindex="0" class="prism-code language-bash codeBlock_U6z7 thin-scrollbar" style="color:#d4d4d4;background-color:#1e1e1e"><code class="codeBlockLines_qR4p"><span class="token-line" style="color:#d4d4d4"><span class="token function">yarn</span><span class="token plain"> </span><span class="token function">add</span><span class="token plain"> my-theme-name --exact</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_ycDu clean-btn">Copy</button></div></div><p>You don&#x27;t have to restart CMS, your Theme will be found and displayed in the Admin panel. Now you can set it as active to see at the frontend.</p></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/features/scalability"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« Deployment and Scalability</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/docs/development/plugin-development"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Plugin development »</div></a></div></nav></div></div><div class="col col--3"><div class="tableOfContents_thVJ thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#create-a-project" class="table-of-contents__link">Create a project</a></li><li><a href="#project-structure" class="table-of-contents__link">Project structure</a></li><li><a href="#compile" class="table-of-contents__link">Compile</a></li><li><a href="#data-fetching" class="table-of-contents__link">Data fetching</a><ul><li><a href="#api" class="table-of-contents__link">API</a></li><li><a href="#monolithic-data-fetching" class="table-of-contents__link">Monolithic data fetching</a></li></ul></li><li><a href="#theme-editor-support" class="table-of-contents__link">Theme Editor support</a></li><li><a href="#configure-pages" class="table-of-contents__link">Configure pages</a><ul><li><a href="#page-config-properties" class="table-of-contents__link">Page config properties:</a></li><li><a href="#default-pages" class="table-of-contents__link">Default pages</a></li></ul></li><li><a href="#use-plugins" class="table-of-contents__link">Use Plugins</a><ul><li><a href="#ship-theme-with-plugins" class="table-of-contents__link">Ship Theme with Plugins</a></li></ul></li><li><a href="#generic-pages" class="table-of-contents__link">Generic pages</a><ul><li><a href="#multiple-generic-layouts" class="table-of-contents__link">Multiple generic layouts</a></li></ul></li><li><a href="#publish" class="table-of-contents__link">Publish</a><ul><li><a href="#publish-in-the-cromwell-cms-market" class="table-of-contents__link">Publish in the Cromwell CMS market</a></li></ul></li><li><a href="#install" class="table-of-contents__link">Install</a><ul><li><a href="#install-from-npm-registry" class="table-of-contents__link">Install from npm registry</a></li></ul></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links">
57<div class="col footer__col"><div class="footer__title">Documentation</div><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs/overview/intro">Overview</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/features/overview">Features</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/development/theme-development">Development</a></li><li class="footer__item"><a class="footer__link-item" href="/latest-frontend-dependencies">Frontend dependencies</a></li></ul></div><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items"><li class="footer__item"><a href="https://discord.gg/mxmJNSZ2gn" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>Discord<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li><li class="footer__item"><a href="https://github.com/CromwellCMS/Cromwell/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>Issues<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li></ul></div><div class="col footer__col"><div class="footer__title">More</div><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">Blog</a></li><li class="footer__item"><a href="https://github.com/CromwellCMS/Cromwell" target="_blank" rel="noopener noreferrer" class="footer__link-item"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_OX1T"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></li><li class="footer__item"><a class="footer__link-item" href="/contacts">Contacts</a></li><li class="footer__item"><a class="footer__link-item" href="/funding">Funding</a></li><li class="footer__item"><a class="footer__link-item" href="/attribution">Attribution</a></li></ul></div></div><div class="logoContainer_yqgz"><div class="logo_JrwJ"></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2022 Cromwell CMS</div></div></div><div>
vendor: 119 bytes, lines 57-58
57
58          <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
vendor: 63 bytes, line 58
58<script async src="https://www.googletagmanager.com/gtag/js?id=
58G-W8QY5D61KR
vendor: 22 bytes, lines 58-59
58"></script>
59          
59<script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-W8QY5D61KR")</script>
59
60        </div></footer></div>
61<script src="/assets/js/runtime~main.a8162b3a.js"></script>
vendor: 1 bytes, line 61
61
62<script src="/assets/js/main.78c54909.js"></script>
vendor: 1 bytes, line 62
62
63<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"56517f4b0f804e8a814b9550f8963a9a","r":1,"spa":2}' crossorigin="anonymous"></script>
63
64</body>
65</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.