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

Modular Architecture for Building Content Websites

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

Souvik Das Gupta

September 28, 2018
Tweet

More Decks by Souvik Das Gupta

Other Decks in Design

Transcript

  1. Modular Architecture for
    Building Content Websites

    View Slide

  2. Hi! I’m Souvik.
    @souvikdg

    View Slide

  3. Miranj

    View Slide

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

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. We like tackling projects
    that are content-heavy.

    View Slide

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

    View Slide

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

    View Slide

  13. Page Page
    Website
    Page

    View Slide

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

    View Slide

  15. Page Page
    Website
    Page
    n = pages

    View Slide

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

    View Slide

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

    View Slide

  18. Section Section
    Website
    Section
    Page Page Page
    Page
    Page Page Page
    Template Template
    Template
    n = templates

    View Slide

  19. Section Section
    Website
    Blog Section
    Page Page
    Post
    Page
    Page Page
    Post
    Template
    Template
    Template Post
    Post

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

  24. Shift towards

    Modular Thinking

    View Slide

  25. Shift towards

    Modular Thinking

    View Slide

  26. Modularity is

    intrinsic to the Web

    View Slide

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

    View Slide


  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

    View Slide


  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

    View Slide


  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

    View Slide


  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

    View Slide


  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

    View Slide


  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

    View Slide


  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

    View Slide

  35. Modular Design
    =
    Evolvable + Decoupled + Reusable

    View Slide

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

    View Slide

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

    View Slide

  38. UI/UX Patterns…

    View Slide

  39. View Slide

  40. Pattern Libraries…

    View Slide

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

    View Slide

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

    View Slide

  43. Style Guides…

    View Slide

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

    View Slide

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

    View Slide

  46. View Slide

  47. View Slide

  48. Components

    View Slide

  49. View Slide

  50. View Slide

  51. Layouts

    View Slide

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

    View Slide

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

    View Slide

  54. Stacking + Nesting

    View Slide

  55. View Slide

  56. “Content Builders”

    View Slide

  57. View Slide

  58. Matrix
    The universally loved feature in Craft CMS

    View Slide

  59. In 2013…

    View Slide

  60. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  67. Content is deeply interconnected.

    View Slide

  68. Content is deeply interdependent.

    View Slide

  69. Every piece of content 

    needs to appear across 

    multiple pages and sections.

    View Slide

  70. Treating page-level templates as 

    monolithic units is inefficient.

    View Slide

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

    View Slide

  72. Discipline + Consistency + Reuse

    View Slide

  73. View Slide

  74. View Slide

  75. View Slide

  76. Post
    Hiker
    About Us

    View Slide

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

    View Slide

  78. Post?
    Hiker?
    About Us?
    Inferior Content UX

    View Slide


  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)

    View Slide

  80. Is this a side-effect
    of a modular approach?

    View Slide

  81. Not really.

    View Slide

  82. User Interface

    View Slide

  83. Dependency Direction
    Content User Interface

    View Slide

  84. Dependency Direction
    User Interface Content

    View Slide


  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)

    View Slide

  86. Embrace content and 

    yet achieve modularity

    View Slide

  87. Components Layouts

    View Slide

  88. ? Layouts
    Components

    View Slide

  89. Layouts
    Components
    Content

    View Slide

  90. Content-first Approach

    View Slide

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

    View Slide

  92. 1. Content Modelling
    Content Strategy and Information Architecture

    View Slide

  93. Layouts
    Components
    Content

    View Slide

  94. Structured Content

    View Slide

  95. Structured Content
    Information or content that is organised in a predictable way
    and is usually classified with metadata.

    View Slide

  96. In a conference website…

    View Slide

  97. Speaker

    View Slide

  98. Speaker
    First Name
    Biography
    Profile Picture
    Last Name
    Role
    Organisation
    Twitter Handle
    Location

    View Slide

  99. Content Types

    View Slide

  100. We refer to the individual 

    content instances as Objects.

    View Slide

  101. Content Modelling
    1. Identify the objects (content types)
    2. Define the objects (models)
    3. Map relationships between objects

    View Slide

  102. In Craft CMS you’re already
    working with Objects.

    View Slide

  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

    View Slide

  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

    View Slide

  105. Taxonomies are first-class objects.

    View Slide

  106. Layouts
    Components
    Content

    View Slide

  107. Layouts
    Components
    Objects
    (Structured Content)

    View Slide

  108. 2. Representing Objects
    Content Strategy leading to Design

    View Slide

  109. Let’s look at a popular website…

    View Slide

  110. View Slide

  111. View Slide

  112. View Slide

  113. View Slide

  114. Objects have many
    representations.

    View Slide

  115. Objects have many
    representations.

    View Slide

  116. View Slide

  117. View Slide

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

    View Slide

  119. View Slide

  120. View Slide

  121. View Slide

  122. View Slide

  123. View Slide

  124. Same object.
    Multiple representations.

    View Slide

  125. Objects need
    different representations.

    View Slide

  126. Movies

    View Slide

  127. Movies
    Title
    Poster
    Trailer
    Full-length

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  133. Views aren’t tied to 

    any specific visual design.

    View Slide

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

    View Slide

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

    View Slide

  136. Snippet
    Teaser
    Embed
    Detail
    Speaker Talk

    View Slide

  137. Snippet
    Teaser
    Embed
    Detail
    Speaker Talk
    “That’s plenty of
    variants to manage!”

    View Slide

  138. Stacking Nesting

    View Slide

  139. Stacking Nesting Cascading

    View Slide

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

    View Slide

  141. Snippet
    Teaser
    Embed
    Detail
    Speaker Talk

    View Slide

  142. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

  143. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

  144. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

  145. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

  146. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

  147. Snippet
    Teaser
    Embed
    Speaker Talk
    Detail

    View Slide

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

    View Slide

  149. All interfaces are
    powered by views.

    View Slide

  150. View Slide

  151. View Slide

  152. View Slide

  153. View Slide

  154. View Slide

  155. View Slide

  156. View Slide

  157. View Slide

  158. View Slide

  159. View Slide

  160. View Slide

  161. View Slide

  162. View Slide

  163. View Slide

  164. View Slide

  165. View Slide

  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.

    View Slide

  167. Layouts
    Components
    Object
    (Structured Content)
    s

    View Slide

  168. Layouts
    Components
    Views
    (Object Representations)

    View Slide

  169. Components
    Views Layouts

    View Slide

  170. 3. Templating
    Implementation and Development

    View Slide

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

    View Slide

  172. Components
    Views Layouts

    View Slide

  173. templates/
    _layouts
    "
    _views
    " _components
    "

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  178. Separation of Concerns
    Components Layouts
    Views
    Render

    a UI Component
    Render 

    an object
    Provide scaffolding

    for laying out the content

    View Slide

  179. Components
    Views Layouts
    Dependency Direction

    View Slide

  180. Components
    Views Layouts
    Components
    Views Layouts

    View Slide

  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

    View Slide

  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)

    View Slide

  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)

    View Slide

  184. {% block detail_main %}



    {% block detail_header_content %}

    {{ entry.title }}

    {% endblock %}



    {% block detail_body %}


    {% block detail_body_content %}

    {% for component in entry.body.all() %}


    {% include '_components/' ~ component.type 

    with { self: component } only %}


    {% endfor %}

    {% endblock %}


    {% 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

    View Slide

  185. {% block detail_main %}



    {% block detail_header_content %}

    {{ entry.title }}

    {% endblock %}



    {% block detail_body %}


    {% block detail_body_content %}

    {% for component in entry.body.all() %}


    {% include '_components/' ~ component.type 

    with { self: component } only %}


    {% endfor %}

    {% endblock %}


    {% 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

    View Slide

  186. {% block detail_main %}



    {% block detail_header_content %}

    {{ entry.title }}

    {% endblock %}



    {% block detail_body %}


    {% block detail_body_content %}

    {% for component in entry.body.all() %}


    {% include '_components/' ~ component.type 

    with { self: component } only %}


    {% endfor %}

    {% endblock %}


    {% 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

    View Slide

  187. {% extends '_layouts/fragment' %}




    {% block component_content %}


    {{ self.text }}


    {% 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

    View Slide

  188. {% extends '_layouts/fragment' %}




    {% block component_content %}


    {{ self.text }}


    {% 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

    View Slide

  189. {% extends '_layouts/fragment' %}




    {% block component_content %}


    {{ self.text }}


    {% 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

    View Slide

  190. {% extends '_layouts/fragment' %}




    {% block component_content %}


    {{ self.text }}


    {% 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?

    View Slide

  191. Components
    Views Layouts
    Components
    Views Layouts

    View Slide

  192. Components
    Views Layo
    Speakers
    Talks

    View Slide

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

    View Slide

  194. _components

    templates/
    _layouts
    "
    details
    teasers
    ! !
    snippets
    !
    default.twig default.twig
    speakers.twig
    default.twig
    speakers.twig
    talks.twig
    "
    _views
    ! "

    View Slide

  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() }} {# {{ entry.title }} #}




    {# Job Title and Twitter #}

    {{ entry.jobTitle }}



    _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

    View Slide

  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() }} {# {{ entry.title }} #}




    {# Job Title and Twitter #}

    {{ entry.jobTitle }}



    _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

    View Slide

  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() }} {# {{ entry.title }} #}




    {# Job Title and Twitter #}

    {{ entry.jobTitle }}



    _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

    View Slide

  198. {% set photo = entry.photo.one() %}

    {% include '_components/image' with {

    self: photo,

    style: 'round',

    } %}


    {# Name #}

    {{ parent() }} {# {{ entry.title }} #}




    {# Job Title and Twitter #}

    {{ entry.jobTitle }}



    @{{ entry.twitter }}



    {% 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

    View Slide

  199. {% set photo = entry.photo.one() %}

    {% include '_components/image' with {

    self: photo,

    style: 'round',

    } %}


    {# Name #}

    {{ parent() }} {# {{ entry.title }} #}




    {# Job Title and Twitter #}

    {{ entry.jobTitle }}



    @{{ entry.twitter }}



    {% 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

    View Slide

  200. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {# 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

    View Slide

  201. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {# 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

    View Slide

  202. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {# 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

    View Slide

  203. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {# 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

    View Slide

  204. Invoking a View
    1. Which view?
    2. Which variant?
    3. Which template file?

    View Slide

  205. Components
    Views Layo
    Speakers
    Talks

    View Slide

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

    View Slide

  207. _components

    templates/
    _layouts
    "
    details
    teasers
    ! !
    snippets
    !
    default.twig default.twig
    speakers.twig
    default.twig
    speakers.twig
    talks.twig
    "
    _views
    ! "

    View Slide

  208. How to invoke a view when the
    template file is unknown?

    View Slide

  209. Router

    View Slide

  210. Router
    1. Target a desired view
    2. Find the most specific template based
    on an order of precedence
    3. Invoke the template

    View Slide

  211. Components
    Views Layo
    Speakers
    Talks

    View Slide

  212. Compo
    Views
    Speakers
    Talks
    Routers

    View Slide

  213. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {% include ‘_routers/snippet’
    with { entry: talk } %}


    _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

    View Slide

  214. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {% include ‘_routers/snippet’
    with { entry: talk } %}


    _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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  220. {% block snippet_main %}

    {% block snippet_content %}


    {{ entry.title }}


    {% endblock %}

    {% 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

    View Slide

  221. {% block snippet_main %}

    {% block snippet_content %}


    {{ entry.title }}


    {% endblock %}

    {% 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

    View Slide

  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

    View Slide

  223. Compo
    Views
    Speakers
    Talks
    Routers

    View Slide

  224. Compo
    Views
    Speakers
    Talks
    Routers

    View Slide

  225. Views can be nested in any order.

    View Slide

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

    View Slide

  227. Routers Views Components Layouts

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  231. View Slide

  232. View Slide

  233. View Slide

  234. View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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?

    View Slide

  243. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {% include '_routers/snippet'
    with { entry: talk } %} 


    _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

    View Slide

  244. {% block detail_body_after %}


    {# 

    Talks by this Speaker 

    #}


    {% set talks = craft.entries({

    section: 'talks',

    relatedTo: entry,

    }).all() %}


    {% if talks|length %} 


    Talks by {{ entry.firstName }}



    {% for talk in talks %}

    {% block related_item %}


    {% include ‘_routers/teaser'
    with { entry: talk } %}


    _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

    View Slide

  245. Recap
    1. Content Modelling
    3. Translate Modules

    into Templates
    2. Identify Representations

    and Modules
    Objects
    Views
    Views (Objects)
    Routers
    +

    View Slide

  246. n = views + object-types

    View Slide

  247. Routers Views Components Layouts

    View Slide

  248. Modular Architecture for
    Building Content Websites

    View Slide

  249. Decoupled
    Evolvable
    Reusable

    View Slide

  250. Decoupled
    Evolvable
    Reusable Components
    Views
    Layouts
    Decoupled

    View Slide

  251. Decoupled
    Evolvable
    Reusable Nesting
    Stacking
    Cascading
    Reusable


    View Slide

  252. Decoupled
    Evolvable
    Reusable
    Cascading
    Evolvable



    Extensible
    +

    View Slide

  253. Decoupled
    Evolvable
    Reusable
    Evolvable

    Decoupled

    Reusable

    View Slide

  254. Flexible and Maintainable.

    View Slide

  255. Scales better.

    View Slide

  256. View Slide

  257. Elements + Routing + Twig

    View Slide

  258. This architecture does not
    replace a Design System or a
    “Content Builder” approach.

    View Slide

  259. This is a complimentary system.

    View Slide

  260. Works in projects big or small.

    View Slide

  261. #
    @souvikdg
    [email protected]

    View Slide