Adding modules in Twig - HL Vanilla Community
<main> <article class="userContent"> <p><em>These docs are meant for developers working on Enterprise level communities creating file based themes in github. </em></p><p><em>If you are using the Theme Editor UI, please refer to this documentation: </em></p><div class="js-embed embedResponsive" data-embedjson="{"body":"Pockets can be used to enhance your site in two ways: Adding Vanilla Widgets (formerly known as Modules) Adding areas to your forum where you can inject custom HTML or Javascript into your theme Pockets are available on all plan levels. To activate it, simply locate it in your addon list (\/dashboard\/settings\/addons) and…","photoUrl":"https:\/\/us.v-cdn.net\/6030677\/uploads\/VWGAXAF5OFCO\/microsoftteams-image.png","url":"https:\/\/success.vanillaforums.com\/kb\/articles\/366-using-pockets-widgets-to-enhance-your-theme","embedType":"link","name":"Using Pockets & Widgets to Enhance your Theme - Vanilla Success"}"> <a href="https://success.vanillaforums.com/kb/articles/366-using-pockets-widgets-to-enhance-your-theme" rel="nofollow noreferrer ugc"> https://success.vanillaforums.com/kb/articles/366-using-pockets-widgets-to-enhance-your-theme </a> </div><p><br></p><h2 data-id="adding-modules-in-twig">Adding Modules in Twig</h2><p>To add a theme module in <a href="https://twig.symfony.com/" rel="nofollow noreferrer ugc">twig</a>, make use of the <code class="code codeInline" spellcheck="false" tabindex="0">renderModule</code> function.</p><p>Example:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">{{ renderModule("NewEventsModule", { limit: 20, mode: "past", } ) }} </pre><p>The first parameter is the name of the module and the second are props. </p><h2 data-id="available-modules">Available Modules</h2><h2 data-id="neweventsmodule">NewEventsModule</h2><p>This module allows users to see upcoming events at a glance. It's meant to be compact and to be used in a side panel.</p><p>N.B. The module appears by default in the side-panel when Groups & Events is enabled and you have upcoming events.</p><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/UC3NWBWQ2NKL/screen-shot-2020-09-23-at-08-06-30.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/UC3NWBWQ2NKL/screen-shot-2020-09-23-at-08-06-30.png" alt="Screen Shot 2020-09-23 at 08.06.30.png" height="728" width="530" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <h4 data-id="properties">Properties</h4><p><strong><em>These properties are option, you do not need to put any of these props for it to render. If no props are added, our defaults will be used</em></strong></p><ul><li><code class="code codeInline" spellcheck="false" tabindex="0">parentRecordID</code> Record ID of the parent where the event was created.</li><li><code class="code codeInline" spellcheck="false" tabindex="0">parentRecordType</code> Record type of the parent where the event was created (ie. group/category</li><li><code class="code codeInline" spellcheck="false" tabindex="0">mode</code> Range of events. See below for possible values<ul><li>"upcoming"</li><li>"all"</li><li>"past"</li></ul></li></ul><h4 data-id="requirementsdependencies">Requirements/dependencies</h4><ul><li>Enable the Groups & Events add-on</li><li>For non Foundation based themes, you will a CSM to enable the<code class="code codeInline" spellcheck="false" tabindex="0">themeFeatures.NewEventsPage</code> feature flag</li></ul><h4 data-id="sample-code">Sample code</h4><pre class="code codeBlock" spellcheck="false" tabindex="0">// Default, no props {{ renderModule("NewEventsModule") }} // Or customized with props {{ renderModule("NewEventsModule", { limit: 20, mode: "past", } ) }} </pre><h2 data-id="leaderboard">Leaderboard</h2><p>Display the top users in your community.</p><p>N.B. This module appears by default on your forum's Activity Page when Badges is enabled</p><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/J2YY3G6RNZ5X/screen-shot-2020-09-23-at-08-41-22.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/J2YY3G6RNZ5X/screen-shot-2020-09-23-at-08-41-22.png" alt="Screen Shot 2020-09-23 at 08.41.22.png" height="814" width="604" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <h4 data-id="properties-1">Properties</h4><p><strong><em>These properties are option, you do not need to put any of these props for it to render. If no props are added, our defaults will be used</em></strong></p><ul><li><code class="code codeInline" spellcheck="false" tabindex="0">SlotType</code> See below for values<ul><li>"w" - Gives this weeks leaders</li><li>"m" - Gives this month's leaders</li><li>"a" - Gives all time leaders</li></ul></li><li><code class="code codeInline" spellcheck="false" tabindex="0">Limit</code> maximum number of results</li><li><code class="code codeInline" spellcheck="false" tabindex="0">CategoryID</code> Only look up one category</li></ul><h4 data-id="required-plugins">Required Plugins</h4><ul><li>Badges</li></ul><h4 data-id="sample-code-1">Sample code</h4><pre class="code codeBlock" spellcheck="false" tabindex="0">// Default, no props {{ renderModule("LeaderBoardModule") }} // Or customized with props {{ renderModule("LeaderBoardModule", { SlotType: "a", CategoryID: 1 } ) }} </pre><h4></h4><h3 data-id="discussions">Discussions</h3><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/08T08XLD2J7P/screen-shot-2020-09-23-at-10-21-16.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/08T08XLD2J7P/screen-shot-2020-09-23-at-10-21-16.png" alt="Screen Shot 2020-09-23 at 10.21.16.png" height="956" width="1156" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <p>Displays forum discussions in a custom location. Note that you <strong>will need</strong> to style this component. It's used to insert discussions where we don't by default, so it's not fully styled.</p><h4 data-id="properties-2">Properties</h4><p><strong><em>These properties are option, you do not need to put any of these props for it to render. If no props are added, our defaults will be used</em></strong></p><ul><li><code class="code codeInline" spellcheck="false" tabindex="0">Limit</code> maximum number of results</li><li><code class="code codeInline" spellcheck="false" tabindex="0">showPhotos</code> Do you want the user avatars?</li><li><code class="code codeInline" spellcheck="false" tabindex="0">categoryIDs</code> For displaying discussions from specific categories. Note that this is an array, not an int or string</li></ul><h4 data-id="required-plugins-1">Required Plugins</h4><p>None</p><h4 data-id="sample-code-2">Sample code</h4><pre class="code codeBlock" spellcheck="false" tabindex="0">// Default, no props {{ renderModule("DiscussionsModule") }} // Or customized with props {{ renderModule("DiscussionsModule", { limit: 40, showPhotos: true, categoryIDs: [1, 2, 5], } ) }} </pre><h3 data-id="tags">Tags</h3><p>Display popular tags (aka tag cloud).</p><p>N.B. This module appears by default in your site's side-panel when the Popular Tags add-on is enabled</p><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/PM3E14VO2JZ7/screen-shot-2020-09-23-at-08-53-55.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/PM3E14VO2JZ7/screen-shot-2020-09-23-at-08-53-55.png" alt="Screen Shot 2020-09-23 at 08.53.55.png" height="218" width="546" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <h4 data-id="properties-3">Properties</h4><p><strong><em>These properties are option, you do not need to put any of these props for it to render. If no props are added, our defaults will be used</em></strong></p><ul><li><code class="code codeInline" spellcheck="false" tabindex="0">Context</code> What scope are we searching tags in<ul><li>"Global" - Search everywhere</li><li>"Discussion" - Search in current discussion (<strong>Note that you do not explicitly set this one.</strong> If you don't set the context, it will autodetect if you're in a discussion)</li><li>"Category" - Search current category (<strong>Note that you do not explicitly set this one.</strong> If you don't set the context, it will autodetect if you're in a category)</li></ul></li></ul><h4 data-id="required-plugins-2">Required Plugins</h4><p>None</p><h4 data-id="sample-code-3">Sample code</h4><pre class="code codeBlock" spellcheck="false" tabindex="0">// Default, no props {{ renderModule("DiscussionsListModule") }} // Or customized with props {{ renderModule("DiscussionsListModule", { Context="Global" } ) }} </pre><h3 data-id="who's-online">Who's online</h3><p>See which other members are online currently.</p><p>N.B. This module is enabled by default in your sites side-panel when the Online add-on is enabled</p><p><br></p><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/4LPBMCF1GT6Y/screen-shot-2020-09-23-at-09-04-18.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/4LPBMCF1GT6Y/screen-shot-2020-09-23-at-09-04-18.png" alt="Screen Shot 2020-09-23 at 09.04.18.png" height="366" width="564" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <h4 data-id="properties-4">Properties</h4><p>None</p><h4 data-id="required-plugins-3">Required Plugins</h4><p>Online</p><h4 data-id="sample-code-4">Sample code</h4><pre class="code codeBlock" spellcheck="false" tabindex="0">// Default, no props {{ renderModule("WhosOnlineModule") }} </pre><h2 data-id="advanced">Advanced</h2><p>For the end user, there should be no difference using PHP vs React modules. I'm documenting it here for more advanced users. PHP only modules extend <code class="code codeInline" spellcheck="false" tabindex="0">Gdn_Module</code> and the react modules extend <code class="code codeInline" spellcheck="false" tabindex="0">AbstractReactModule</code> (which, extends <code class="code codeInline" spellcheck="false" tabindex="0">Gdn_Module</code>).</p><h3 data-id="custom-react-modules">Custom React Modules</h3><p>If you make a custom component, you'll need to first register it with <code class="code codeInline" spellcheck="false" tabindex="0">addComponent</code> in an entry point. Likely from your theme: <code class="code codeInline" spellcheck="false" tabindex="0">[your theme]/src/scripts/entries/forum.tsx</code>. Core modules are already added.</p><pre class="code codeBlock" spellcheck="false" tabindex="0">addComponent("my-new-component", MyNewComponent); </pre><p>This prevents crashing if the component doesn't exist.</p><p>AbstractReactModule's <code class="code codeInline" spellcheck="false" tabindex="0">toString</code> function outputs a div with <code class="code codeInline" spellcheck="false" tabindex="0">data-react</code> with the component name and <code class="code codeInline" spellcheck="false" tabindex="0">data-props</code>. These are picked up by JS, the component is looked up in the component registry and gets passed the props with the proper encoding. </p><h3 data-id="under-the-hood">Under the hood</h3><p>Now that you've got everything set up, you can use the <code class="code codeInline" spellcheck="false" tabindex="0">renderModule</code> and call your component as you would any other!</p><h4 data-id="outputting-your-component">Outputting your component</h4><p><code class="code codeInline" spellcheck="false" tabindex="0">cssWrapperClass</code> is optional and is for adding a class to the wrapper div that contains your component. Sometimes needed for theming purposes.</p><p><code class="code codeInline" spellcheck="false" tabindex="0">renderComponent</code> Sometimes you may want to not render a module under certain circumstances. For example, if you're displaying a list, you may want to not render if it it's empty. This is the function to do it. it will default to <code class="code codeInline" spellcheck="false" tabindex="0">true</code> so only overwrite if you've got some logic to determine if it should show or not.</p><h4 data-id="optional-functions-for-abstractreactmodule">Optional functions for AbstractReactModule</h4><p><code class="code codeInline" spellcheck="false" tabindex="0">getComponentName</code> the name of the component. This needs to match exactly the name used when the component was registered with <code class="code codeInline" spellcheck="false" tabindex="0">addComponent</code>. It'll be the lower cased hyphenated name described above.</p><p><code class="code codeInline" spellcheck="false" tabindex="0">getProps</code> returns the props in an array to be passed to the react component. </p><h4 data-id="required-functions-for-abstractreactmodule">Required functions for AbstractReactModule</h4><p>Next, create a class to extend <code class="code codeInline" spellcheck="false" tabindex="0">AbstractReactModule</code>.</p><p>Now that your component is registered, we need to create the module so we can call it in <a href="https://twig.symfony.com/" rel="nofollow noreferrer ugc">Twig</a>.</p><p>The first parameter is the name of the component, lower cased and hyphenated. The second parameter is the name of the react component, with no extension.</p> </article> </main>