Database driven content elements with TypoScript

For wunderbar-asia.com we added the ability to change the list of dishes by a database. You can see that here: http://www.wunderbar-asia.com/menu.html. The sites requirement for this task were quite low. In fact, each dish is just presented with a title, its picture and some description text. We wanted the flexibility of creating the dishes by Typo3 directly but without the complexity and workload of creating a full-blown MVC module. For this task, TypoScript came to the rescue.

The procedure is quite simple:

  1. Create the necessary database tables in the extension Kickstarter
  2. Create the contents via the list module
  3. Write the TypoScript necessary
  4. Include the element on a page.

Part 1 is quite easy to do, just open kickstarter and create the tables. (Via Ext Manager / Create new Extension) – you might need to install kickstarter first.

Part 2 is also easy, pick a page to create the records and make sure to remember it’s PID.

Part 3 is to create the TypoScript code. I had put it in the created extensions static/wunderbar/ directory in the file called setup.txt:

 

 

dishes.main_list = COA
dishes.main_list.1 = COA
dishes.main_list.1 {
  10 = CONTENT
  10  {
    table = tx_wunderbar_dishes
    select {
      selectFields = uid, name, description, picture
      pidInList = 73

      where = sys_language_uid=###language###
      markers {
         language.data = GP:L
      }
    }
    renderObj = COA
    renderObj {
      stdWrap.wrap = |###SPLITTER###
      1 = TEXT
      1.wrap = <a href="|#wunderbar_dish_{field:uid}" rel="shadowbox;width=650;height=550" title="
      1.insertData = 1
      1.typolink {
        parameter.data=TSFE:id
        returnLast=url
      }

      5 = TEXT
      5.field = name

      7 = TEXT
      7.value = ">

      10 = IMAGE
      10.file.import.field = picture
      10.file.import = uploads/tx_wunderbar/
      10.file.maxH = 180
      10.file.maxW = 250

      15 = TEXT
      15.wrap = </a><span><a href="|#wunderbar_dish_{field:uid}" rel="shadowbox;width=650;height=550" title="
      15.insertData = 1
      15.typolink {
        parameter.data=TSFE:id
        returnLast=url
      }

      17 = TEXT
      17.field = name

      19 = TEXT
      19.value = ">

      21 = TEXT
      21.field = name

      23 = TEXT
      23.value = </a></span>
    }
  }
  stdWrap.split {
    token = ###SPLITTER###
    cObjNum = 1 || 2 || 3 || 1 || 2 || 3 || 1 || 2 || 3 || 1 || 2 || 3 || 1 || 2 || 3 || 1 || 2 || 3
    1.wrap = <li>|</li>
    1.if.isTrue.current = 1
    1.current = 1
    2.wrap = <li>|</li>
    2.if.isTrue.current = 1
    2.current = 1
    3.wrap = <li class="last">|</li>
    3.if.isTrue.current = 1
    3.current = 1
  }
}
dishes.main_list.1.stdWrap.outerWrap = <ul class="menu_product">|</ul>
dishes.main_list.2 = COA
dishes.main_list.2 {
  10 = CONTENT
  10  {
    table = tx_wunderbar_dishes
    select {
      selectFields = uid, name, description, picture
      pidInList = 73

      where = sys_language_uid=###language###
      markers {
         language.data = GP:L
      }
    }
    renderObj = COA
    renderObj {
      1 = TEXT
      1.value= <div id="wunderbar_dish_{field:uid}" style="display:none;"><div class="menu_large_content">
      1.insertData = 1

      10 = IMAGE
      10.file.import.field = picture
      10.file.import = uploads/tx_wunderbar/
      10.file.maxW = 600
      10.file.maxH = 450

      15 = TEXT
      15.value = <p class="des">{field:description}</p>
      15.insertData = 1

      23 = TEXT
      23.value = </div></div>
    }
  }
}

Some of the things I like to share about this TypoScript code, cause it took me a while to find them out:

  1. Yes, I should’ve used the TEMPLATE object – and next time I will. Promise. 🙂
  2. I had to use the ###SPLITTER### markers because some CSS was requiring to include ‘class=”last”‘ markers to create a proper line-break. Next time I would probably require the HTML/CSS to not have any of these markers or rely on jQuery to create them dynamically.
  3. Next time I would move the fix values (like the PID) into constants from the start.
  4. You may wonder about the extra block containing the marker for the language in the where part of the query.
      where = sys_language_uid=###language###
      markers {
         language.data = GP:L
      }

As it turns out, select and CONTENT have some problems if your pages are configured for multiple language using content_fallback – as suggested by TemplaVoila. Hence (I didn’t want to import any patches) this workaround.

Part 4 is on how to integrate this piece of TypoScript in the page. Naturally you could simply import it in the Template (using PAGE.xxx) but this wasn’t flexible enough for our use. We wanted to have this code wherever we want it and independent from the actual template. Also, as we are using TemplaVoila for our sites, static TS templates were not applicable. Luckily there is a extension in the TER called tscobj. Using this extension, it’s possible to include arbitrary pieces of TS in any place within a page.

Conclusion

Using TypoScript to create such pages is not a bad idea. I enjoyed to NOT write any PHP for this requirement, to NOT run any SQL queries myself and to NOT use a template engine. (though, I should have used the TEMPLATE TypoScript object..).