Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modular Architecture for Building Content Websites

F94f921203292a9ef700807e9cd5061f?s=47 Souvik Das Gupta
September 28, 2018

Modular Architecture for Building Content Websites

Craft is great at not making any assumptions about your content. It puts a bit more onus on you but in turn enables you to create a unique, hand-crafted information architecture for your website. However, the entire exercise from content modelling to templating can get daunting when working with a large content website. This talk will simplify the exercise by suggesting an approach that is loosely based on the OOUX methodology while keeping reuse and scale in mind. We’ll walk through the process right from identifying content objects to abstracting reusable patterns and finally organising Twig templates in Craft.

Presented at Dot All 2018 (Berlin): https://dotall.com/sessions/architecting-a-content-website

F94f921203292a9ef700807e9cd5061f?s=128

Souvik Das Gupta

September 28, 2018
Tweet

Transcript

  1. Modular Architecture for Building Content Websites

  2. Hi! I’m Souvik. @souvikdg

  3. Miranj

  4. We architect information and design radically simple, future-proof websites.

  5. None
  6. None
  7. None
  8. None
  9. None
  10. We like tackling projects that are content-heavy.

  11. The number of content pieces often run into thousands.

  12. How we think of a website has kept evolving over

    time.
  13. Page Page Website Page

  14. Page Page Website Page Complexity & Size ∝ fn(n)

  15. Page Page Website Page n = pages

  16. Section Section Website Section Page Page Page Page Page Page

    Page
  17. Section Section Website Section Page Page Page Page Page Page

    Page Template Template Template
  18. Section Section Website Section Page Page Page Page Page Page

    Page Template Template Template n = templates
  19. Section Section Website Blog Section Page Page Post Page Page

    Page Post Template Template Template Post Post
  20. Section Section Website Blog Section Page Page Post Page Page

    Page Post Template Template Post Post Template Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Index
  21. Post Post Post Post Post Post Post Post Post Post

    Post Post Post Post Post Post Post Post Post Post Post Post Post Post Index Template Section Section Website Blog Section Page Page Page Page Page Template Template Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post
  22. Post Post Post Post Post Post Post Post Post Post

    Post Post Post Post Post Post Post Post Post Post Post Post Post Post Index Template Section Section Website Blog Section Page Page Page Page Page Template Template Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Taxonomy Taxonomy Taxonomy Taxonomy
  23. Post Post Post Post Post Post Post Post Post Post

    Post Post Post Post Post Post Post Post Post Post Post Post Post Post Index Template Section Section Website Blog Section Page Page Page Page Page Template Template Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Post Taxonomy Taxonomy Taxonomy Taxonomy n = templates (page + index + taxonomy)
  24. Shift towards
 Modular Thinking

  25. Shift towards
 Modular Thinking

  26. Modularity is
 intrinsic to the Web

  27. Modular Design Principles of Design – Tim Berners-Lee (1998) www.w3.org/DesignIssues/Principles.html

  28. “ – Tim Berners-Lee There are lots of reasons for

    modularity. The basic one is that one module 
 can evolve or be replaced without affecting 
 the others. www.w3.org/DesignIssues/Modularity.html
  29. “ – Tim Berners-Lee If the interfaces are clean, and

    there are no side effects, then a developer can redesign a module without having to deeply understand the neighboring modules. www.w3.org/DesignIssues/Modularity.html
  30. “ – Tim Berners-Lee The flip side is that a

    cleanly designed module designed as part of one system can be re-used in other systems. www.w3.org/DesignIssues/Modularity.html
  31. “ – Tim Berners-Lee There are lots of reasons for

    modularity. The basic one is that one module 
 can evolve or be replaced without affecting 
 the others. www.w3.org/DesignIssues/Modularity.html
  32. “ – Tim Berners-Lee There are lots of reasons for

    modularity. The basic one is that one module 
 can evolve or be replaced without affecting 
 the others. www.w3.org/DesignIssues/Modularity.html
  33. “ – Tim Berners-Lee If the interfaces are clean, and

    there are no side effects, then a developer can redesign a module without having to deeply understand the neighboring modules. www.w3.org/DesignIssues/Modularity.html
  34. “ – Tim Berners-Lee The flip side is that a

    cleanly designed module designed as part of one system can be re-used in other systems. www.w3.org/DesignIssues/Modularity.html
  35. Modular Design = Evolvable + Decoupled + Reusable

  36. commons.wikimedia.org/wiki/File:Lego_Color_Bricks.jpg

  37. commons.wikimedia.org/wiki/File:Lego_Color_Bricks.jpg Think Lego!

  38. UI/UX Patterns…

  39. None
  40. Pattern Libraries…

  41. www.flickr.com/photos/antpaniagua/8110356483 Modules that stack.

  42. www.flickr.com/photos/antpaniagua/8110356483

  43. Style Guides…

  44. Atomic Design bradfrost.com/blog/post/atomic-web-design/ Design Systems!

  45. Atomic Design bradfrost.com/blog/post/atomic-web-design/

  46. None
  47. None
  48. Components

  49. None
  50. None
  51. Layouts

  52. pixabay.com/en/matryoshka-russian-doll-russian-toy-2737108 Modules that nest.

  53. pixabay.com/en/matryoshka-russian-doll-russian-toy-2737108

  54. Stacking + Nesting

  55. None
  56. “Content Builders”

  57. None
  58. Matrix The universally loved feature in Craft CMS

  59. In 2013…

  60. None
  61. Spon posals Talks Schedule JSFoo Speakers Talk 1 Talk 2

    Talk 3 Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2
  62. Talks Schedule JSFoo Speakers Talk 1 Talk 2 Talk 3

    Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2 Spon posals
  63. Talks Schedule JSFoo Speakers Talk 1 Talk 2 Talk 3

    Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2 Spon posals
  64. Talks Schedule JSFoo Speakers Talk 1 Talk 2 Talk 3

    Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2 Spon posals
  65. Talks Schedule JSFoo Speakers Talk 1 Talk 2 Talk 3

    Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2 Spon posals
  66. Talks Schedule JSFoo Speakers Talk 1 Talk 2 Talk 3

    Speaker 1 Speaker 2 Speaker 3 Track 1 Track 2 Sponsors Workshops Proposals Past Speakers Featured Talks Venue Hotels Spon posals
  67. Content is deeply interconnected.

  68. Content is deeply interdependent.

  69. Every piece of content 
 needs to appear across 


    multiple pages and sections.
  70. Treating page-level templates as 
 monolithic units is inefficient.

  71. It just wasn’t DRY enough. (Don’t Repeat Yourself)

  72. Discipline + Consistency + Reuse

  73. None
  74. None
  75. None
  76. Post Hiker About Us

  77. Post? Hiker? About Us? Hard to skim Hard to differentiate

    Hard to consume Hard to appreciate
  78. Post? Hiker? About Us? Inferior Content UX

  79. “ – Tom Brinck Contrast and consistency go hand in

    hand. Make similar things look similar. Make different things look different. Usability For The Web (2001)
  80. Is this a side-effect of a modular approach?

  81. Not really.

  82. User Interface

  83. Dependency Direction Content User Interface

  84. Dependency Direction User Interface Content

  85. “ – Josh Clark Pull back from obsession with presentation.

    Start with content. [Designers] have to accept that your content will take many forms.… Seven Deadly Mobile Myths (2012)
  86. Embrace content and 
 yet achieve modularity

  87. Components Layouts

  88. ? Layouts Components

  89. Layouts Components Content

  90. Content-first Approach

  91. 1. Content Modelling 2. Identifying Representations and Modules 3. Translating

    Modules into Templates
  92. 1. Content Modelling Content Strategy and Information Architecture

  93. Layouts Components Content

  94. Structured Content

  95. Structured Content Information or content that is organised in a

    predictable way and is usually classified with metadata.
  96. In a conference website…

  97. Speaker

  98. Speaker First Name Biography Profile Picture Last Name Role Organisation

    Twitter Handle Location
  99. Content Types

  100. We refer to the individual 
 content instances as Objects.

  101. Content Modelling 1. Identify the objects (content types) 2. Define

    the objects (models) 3. Map relationships between objects
  102. In Craft CMS you’re already working with Objects.

  103. 1. Asset 2. Category 3. Entry 4. Globals 5. MatrixBlock

    6. Tag 7. User craft\elements\Asset craft\elements\Category craft\elements\Entry craft\elements\GlobalSet craft\elements\MatrixBlock craft\elements\Tag craft\elements\User
  104. 1. Asset 2. Category 3. Entry 4. Globals 5. MatrixBlock

    6. Tag 7. User craft\elements\Asset craft\elements\Category craft\elements\Entry craft\elements\GlobalSet craft\elements\MatrixBlock craft\elements\Tag craft\elements\User
  105. Taxonomies are first-class objects.

  106. Layouts Components Content

  107. Layouts Components Objects (Structured Content)

  108. 2. Representing Objects Content Strategy leading to Design

  109. Let’s look at a popular website…

  110. None
  111. None
  112. None
  113. None
  114. Objects have many representations.

  115. Objects have many representations.

  116. None
  117. None
  118. “But that’s a very large website. What about smaller websites?”

  119. None
  120. None
  121. None
  122. None
  123. None
  124. Same object. Multiple representations.

  125. Objects need different representations.

  126. Movies

  127. Movies Title Poster Trailer Full-length

  128. Movies Title Poster Trailer Full-length Label Engage Preview Entertain

  129. Movies Title Poster Trailer Full-length Label Engage Preview Entertain

  130. Movies Title Poster Trailer Full-length Label Engage Preview Entertain Views

  131. Objects Snippet Teaser Embed Detail Label Engage Preview Full Information

    Views
  132. Speaker Snippet Teaser Embed Detail Label Engage Preview Full Information

    Views
  133. Views aren’t tied to 
 any specific visual design.

  134. Speaker Snippet Teaser Embed Detail Label Engage Preview Full Information

    Views
  135. Talk Snippet Teaser Embed Detail Label Engage Preview Full Information

    Views
  136. Snippet Teaser Embed Detail Speaker Talk

  137. Snippet Teaser Embed Detail Speaker Talk “That’s plenty of variants

    to manage!”
  138. Stacking Nesting

  139. Stacking Nesting Cascading

  140. www.flickr.com/photos/petechar/15224096659

  141. Snippet Teaser Embed Detail Speaker Talk

  142. Snippet Teaser Embed Speaker Talk Detail

  143. Snippet Teaser Embed Speaker Talk Detail

  144. Snippet Teaser Embed Speaker Talk Detail

  145. Snippet Teaser Embed Speaker Talk Detail

  146. Snippet Teaser Embed Speaker Talk Detail

  147. Snippet Teaser Embed Speaker Talk Detail

  148. www.flickr.com/photos/petechar/15224096659 Modules that Cascade.

  149. All interfaces are powered by views.

  150. None
  151. None
  152. None
  153. None
  154. None
  155. None
  156. None
  157. None
  158. None
  159. None
  160. None
  161. None
  162. None
  163. None
  164. None
  165. None
  166. Views 1. Are the representations of an object. 2. Are

    not tied to a visual design, but rather to a purpose behind the representation. 3. Stack, nest and cascade across all objects. 4. Can evolve (or be replaced) for specific objects.
  167. Layouts Components Object (Structured Content) s

  168. Layouts Components Views (Object Representations)

  169. Components Views Layouts

  170. 3. Templating Implementation and Development

  171. templates/ _entry.twig tracks ! _entry.twig talks ! speakers ! _entry.twig

  172. Components Views Layouts

  173. templates/ _layouts " _views " _components "

  174. templates/ fragment.twig blog.twig page.twig _layouts ! landing.twig _views " _components

    "
  175. banner.twig quote.twig image.twig heading.twig _components ! table.twig text.twig templates/ _layouts

    " _views "
  176. _components templates/ _layouts " details teasers " " snippets "

    " _views ! "
  177. _components templates/ _layouts " details teasers ! ! snippets !

    default.twig default.twig default.twig " _views ! "
  178. Separation of Concerns Components Layouts Views Render
 a UI Component

    Render 
 an object Provide scaffolding
 for laying out the content
  179. Components Views Layouts Dependency Direction

  180. Components Views Layouts Components Views Layouts

  181. 1 2 3 4 5 6 7 8 9 10

    11 12 13 14 15 16 17 18 19 20 21 22 Speaker Page
  182. 1 2 3 4 5 6 7 8 9 10

    11 12 13 14 15 16 17 18 19 20 21 22 Snippet(Talk)
  183. 1 2 3 4 5 6 7 8 9 10

    11 12 13 14 15 16 17 18 19 20 21 22 Detail(Speaker)
  184. {% block detail_main %}
 <article class="detail">
 <header>
 {% block detail_header_content

    %}
 <h1>{{ entry.title }}</h1>
 {% endblock %}
 </header>
 
 {% block detail_body %}
 <main>
 {% block detail_body_content %}
 {% for component in entry.body.all() %}
 
 {% include '_components/' ~ component.type 
 with { self: component } only %}
 
 {% endfor %}
 {% endblock %}
 </main>
 {% endblock %}
 
 {% block detail_body_after %}{% endblock %}
 _views/details/default.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  185. {% block detail_main %}
 <article class="detail">
 <header>
 {% block detail_header_content

    %}
 <h1>{{ entry.title }}</h1>
 {% endblock %}
 </header>
 
 {% block detail_body %}
 <main>
 {% block detail_body_content %}
 {% for component in entry.body.all() %}
 
 {% include '_components/' ~ component.type 
 with { self: component } only %}
 
 {% endfor %}
 {% endblock %}
 </main>
 {% endblock %}
 
 {% block detail_body_after %}{% endblock %}
 _views/details/default.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  186. {% block detail_main %}
 <article class="detail">
 <header>
 {% block detail_header_content

    %}
 <h1>{{ entry.title }}</h1>
 {% endblock %}
 </header>
 
 {% block detail_body %}
 <main>
 {% block detail_body_content %}
 {% for component in entry.body.all() %}
 
 {% include '_components/' ~ component.type 
 with { self: component } only %}
 
 {% endfor %}
 {% endblock %}
 </main>
 {% endblock %}
 
 {% block detail_body_after %}{% endblock %}
 _views/details/default.twig 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  187. {% extends '_layouts/fragment' %}
 
 
 
 {% block component_content

    %}
 <div class="{{ self.class ?? style ?? '' }}">
 {{ self.text }}
 </div>
 {% endblock %} _components/text.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  188. {% extends '_layouts/fragment' %}
 
 
 
 {% block component_content

    %}
 <div class="{{ self.class ?? style ?? '' }}">
 {{ self.text }}
 </div>
 {% endblock %} _components/text.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  189. {% extends '_layouts/fragment' %}
 
 
 
 {% block component_content

    %}
 <div class="{{ self.class ?? style ?? '' }}">
 {{ self.text }}
 </div>
 {% endblock %} _components/text.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  190. {% extends '_layouts/fragment' %}
 
 
 
 {% block component_content

    %}
 <div class="{{ self.class ?? style ?? '' }}">
 {{ self.text }}
 </div>
 {% endblock %} _components/text.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 How will a talk and a speaker view be made different?
  191. Components Views Layouts Components Views Layouts

  192. Components Views Layo Speakers Talks

  193. _components templates/ _layouts " details teasers ! ! snippets !

    default.twig default.twig default.twig " _views ! "
  194. _components ꔇ templates/ _layouts " details teasers ! ! snippets

    ! default.twig default.twig speakers.twig default.twig speakers.twig talks.twig " _views ! "
  195. {% extends '_views/details/default' %}
 
 
 
 {% block detail_header_content

    %}
 
 {# Photo #}
 {% set photo = entry.photo.one() %}
 {% include '_components/image' with {
 self: photo,
 style: 'round',
 } %}
 
 {# Name #}
 {{ parent() }} {# <h1> {{ entry.title }} </h1> #}
 
 <hr>
 
 {# Job Title and Twitter #}
 <p>{{ entry.jobTitle }}</p>
 <p>
 <a href="//twitter.com/{{ entry.twitter }}">
 _views/details/speakers.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  196. {% extends '_views/details/default' %}
 
 
 
 {% block detail_header_content

    %}
 
 {# Photo #}
 {% set photo = entry.photo.one() %}
 {% include '_components/image' with {
 self: photo,
 style: 'round',
 } %}
 
 {# Name #}
 {{ parent() }} {# <h1> {{ entry.title }} </h1> #}
 
 <hr>
 
 {# Job Title and Twitter #}
 <p>{{ entry.jobTitle }}</p>
 <p>
 <a href="//twitter.com/{{ entry.twitter }}">
 _views/details/speakers.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  197. {% extends '_views/details/default' %}
 
 
 
 {% block detail_header_content

    %}
 
 {# Photo #}
 {% set photo = entry.photo.one() %}
 {% include '_components/image' with {
 self: photo,
 style: 'round',
 } %}
 
 {# Name #}
 {{ parent() }} {# <h1> {{ entry.title }} </h1> #}
 
 <hr>
 
 {# Job Title and Twitter #}
 <p>{{ entry.jobTitle }}</p>
 <p>
 <a href="//twitter.com/{{ entry.twitter }}">
 _views/details/speakers.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  198. {% set photo = entry.photo.one() %}
 {% include '_components/image' with

    {
 self: photo,
 style: 'round',
 } %}
 
 {# Name #}
 {{ parent() }} {# <h1> {{ entry.title }} </h1> #}
 
 <hr>
 
 {# Job Title and Twitter #}
 <p>{{ entry.jobTitle }}</p>
 <p>
 <a href="//twitter.com/{{ entry.twitter }}">
 @{{ entry.twitter }}
 </a>
 </p>
 {% endblock %}
 
 
 
 _views/details/speakers.twig 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  199. {% set photo = entry.photo.one() %}
 {% include '_components/image' with

    {
 self: photo,
 style: 'round',
 } %}
 
 {# Name #}
 {{ parent() }} {# <h1> {{ entry.title }} </h1> #}
 
 <hr>
 
 {# Job Title and Twitter #}
 <p>{{ entry.jobTitle }}</p>
 <p>
 <a href="//twitter.com/{{ entry.twitter }}">
 @{{ entry.twitter }}
 </a>
 </p>
 {% endblock %}
 
 
 
 _views/details/speakers.twig 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  200. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {# Invoke a relevant view for the talk object #}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  201. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {# Invoke a relevant view for the talk object #}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  202. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {# Invoke a relevant view for the talk object #}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  203. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {# Invoke a relevant view for the talk object #}
 
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  204. Invoking a View 1. Which view? 2. Which variant? 3.

    Which template file?
  205. Components Views Layo Speakers Talks

  206. Invoking a View 1. Which view? 2. Which variant? 3.

    Which template file?
  207. _components ꔇ templates/ _layouts " details teasers ! ! snippets

    ! default.twig default.twig speakers.twig default.twig speakers.twig talks.twig " _views ! "
  208. How to invoke a view when the template file is

    unknown?
  209. Router

  210. Router 1. Target a desired view 2. Find the most

    specific template based on an order of precedence 3. Invoke the template
  211. Components Views Layo Speakers Talks

  212. Compo Views Speakers Talks Routers

  213. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {% include ‘_routers/snippet’ with { entry: talk } %}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  214. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {% include ‘_routers/snippet’ with { entry: talk } %}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  215. {#
 Snippet Router
 #}
 
 {%- include [
 '_views/snippets/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/snippets/' ~ entry.section ~ '/default',
 '_views/snippets/' ~ entry.section,
 '_views/snippets/default',
 ] -%}
 _routers/snippet.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  216. {#
 Snippet Router
 #}
 
 {%- include [
 '_views/snippets/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/snippets/' ~ entry.section ~ '/default',
 '_views/snippets/' ~ entry.section,
 '_views/snippets/default',
 ] -%}
 _routers/snippet.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  217. {#
 Snippet Router
 #}
 
 {%- include [
 '_views/snippets/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/snippets/' ~ entry.section ~ '/default',
 '_views/snippets/' ~ entry.section,
 '_views/snippets/default',
 ] -%}
 _routers/snippet.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  218. {#
 Snippet Router
 #}
 
 {%- include [
 '_views/snippets/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/snippets/' ~ entry.section ~ '/default',
 '_views/snippets/' ~ entry.section,
 '_views/snippets/default',
 ] -%}
 _routers/snippet.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  219. {#
 Snippet Router
 #}
 
 {%- include [
 '_views/snippets/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/snippets/' ~ entry.section ~ '/default',
 '_views/snippets/' ~ entry.section,
 '_views/snippets/default',
 ] -%}
 _routers/snippet.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  220. {% block snippet_main %} <p> {% block snippet_content %}
 <a

    rel="permalink" href="{{ entry.url }}">
 {{ entry.title }}
 </a> {% endblock %} </p>
 {% endblock %} _views/snippets/default.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  221. {% block snippet_main %} <p> {% block snippet_content %}
 <a

    rel="permalink" href="{{ entry.url }}">
 {{ entry.title }}
 </a> {% endblock %} </p>
 {% endblock %} _views/snippets/default.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  222. {% extends '_views/snippets/default' %}
 
 {% block snippet_content %}
 {{

    entry.year }} – {{ parent() }}
 {% endblock %} _views/snippets/talks.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  223. Compo Views Speakers Talks Routers

  224. Compo Views Speakers Talks Routers

  225. Views can be nested in any order.

  226. Detail (Speaker) Teaser (Talk) Snippet (Track) Detail (Speaker) Snippet (Track)

  227. Routers Views Components Layouts

  228. _views " templates/ _routers " _components " _layouts "

  229. _components " _views ! templates/ _routers ! snippet.twig detail.twig teaser.twig

    page.twig teasers snippets details " " " _layouts "
  230. _components " _views ! templates/ _routers ! snippet.twig detail.twig teaser.twig

    page.twig teasers snippets details " " " _layouts "
  231. None
  232. None
  233. None
  234. None
  235. h/t: Flexible Twig Templates in Craft by Anthony Colangelo and

    Ryan Irelan
  236. h/t: Flexible Twig Templates in Craft by Anthony Colangelo and

    Ryan Irelan
  237. {% extends '_layouts/page' %}
 
 
 
 {% block page_main

    %}
 
 {% include '_routers/detail' with { entry: entry } %}
 
 {% endblock %}
 _routers/page.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  238. {% extends '_layouts/page' %}
 
 
 
 {% block page_main

    %}
 
 {% include '_routers/detail' with { entry: entry } %}
 
 {% endblock %}
 _routers/page.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  239. {% extends '_layouts/page' %}
 
 
 
 {% block page_main

    %}
 
 {% include '_routers/detail' with { entry: entry } %}
 
 {% endblock %}
 _routers/page.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  240. {#
 Detail Router
 #}
 
 {%- include [
 '_views/details/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/details/' ~ entry.section ~ '/default',
 '_views/details/' ~ entry.section,
 '_views/details/default',
 ] -%} _routers/detail.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  241. {#
 Detail Router
 #}
 
 {%- include [
 '_views/details/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/details/' ~ entry.section ~ '/default',
 '_views/details/' ~ entry.section,
 '_views/details/default',
 ] -%} _routers/detail.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  242. {#
 Detail Router
 #}
 
 {%- include [
 '_views/details/' ~

    entry.section ~ '/' ~ entry.type,
 '_views/details/' ~ entry.section ~ '/default',
 '_views/details/' ~ entry.section,
 '_views/details/default',
 ] -%} _routers/detail.twig 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 What if we want to make the related talks a bit more engaging?
  243. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {% include '_routers/snippet' with { entry: talk } %} 
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  244. {% block detail_body_after %}
 
 {# 
 Talks by this

    Speaker 
 #}
 
 {% set talks = craft.entries({
 section: 'talks',
 relatedTo: entry,
 }).all() %}
 
 {% if talks|length %} 
 <section>
 <h2>Talks by {{ entry.firstName }}</h2>
 
 <ul>
 {% for talk in talks %}
 {% block related_item %}
 <li>
 {% include ‘_routers/teaser' with { entry: talk } %}
 </li>
 _views/details/speakers.twig 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  245. Recap 1. Content Modelling 3. Translate Modules
 into Templates 2.

    Identify Representations
 and Modules Objects Views Views (Objects) Routers +
  246. n = views + object-types

  247. Routers Views Components Layouts

  248. Modular Architecture for Building Content Websites

  249. Decoupled Evolvable Reusable

  250. Decoupled Evolvable Reusable Components Views Layouts Decoupled ✓

  251. Decoupled Evolvable Reusable Nesting Stacking Cascading Reusable ✓ ✓

  252. Decoupled Evolvable Reusable Cascading Evolvable ✓ ✓ ✓ Extensible +

  253. Decoupled Evolvable Reusable Evolvable ✓ Decoupled ✓ Reusable ✓

  254. Flexible and Maintainable.

  255. Scales better.

  256. None
  257. Elements + Routing + Twig

  258. This architecture does not replace a Design System or a

    “Content Builder” approach.
  259. This is a complimentary system.

  260. Works in projects big or small.

  261. # @souvikdg souvikdg@miranj.in