May 7, 2009

TYPO3 SEO: keywords from the TypoScript and a page

I like TypoScript! It is a fantastic language. Almost everything is possible. For example, today I had to solve an interesting task. I have to show keywords on the page. Keywords shouls be taken from the page's "Keywords" field and appended by the content of a TypoScript constant. Any of these too could be empty and there should be no extra comma if one of parts is missing. If no keywords are set, there should be no keywords meta on the page. So there are four choices:

  • no keywords at all (no meta tag)
  • keywords from the TypoScript only
  • keywords from the page only
  • keywords from both page and TypoScript
All four cases must be handled properly.
Here is how I solved it:
page.meta.keywords {
  # Set 'current' value
  setCurrent = {$meta.keywords}
  # Set content to match current
  current = 1
  # Prepend page keywords
  prepend = TEXT
  prepend {
  data = page:keywords
  # if empty, return immediately
  trim = 1
  required = 1
  # wrap it
  innerWrap {
    # wrap only if {$meta.keywords} is not empty
    if.isTrue.current = 1
    # We must return a wrap pattern here
    append = TEXT
    append.value = |,
  }
}
}
This plan was like this:
  • set one value
  • if that value is not empty and the second value is not empty, append a comma
  • if the second value is not empty, append it
So far, so good. But there is no way to directly implement in TypoScript with a single property or two! Fortunately page.meta.keywords is a stdWrap. It means I have unlimited possibilities of testing for empty, appending, prepending or replacing values.
I decided to start from the most complex thing (#2 in the list above). How do I test that I need to put comma in between? Obviously I cannjot use properties such as required or if or ifEmpty because they test a single value. So I needed something that tests both values. I set to think and it came to me: if I assign the first value to the current property, I can test it later on while I generate the second value! This is what lines 3 and 5 of the TypoScript about do. The first line sets current value to the TypoScript constant value and the second sets content value to the current value.
Next I want to prepend the keywords from the page record. So I use prepend property, which is a cObject. I set its data property to keywords, trim it and check that it is not empty using the required property. If the value is empty, prepend will return empty value immediately and nothing will be prepended. Cool, right?
Next I must append a comma to the page keywords if and only if the TypoScript constant was not empty. For that I have to use innerWrap. Notice that I cannot use stdWrap property because it executes before the required and I need to wrap only after. Therefore I use innerWrap.
innerWrap is a wrap and fortunately it is also a stdWrap. I use if property to check if current value is not empty. As you remember, this value is the value of the TypoScript constant we set earlier. If it is not empty, the innerWrap should be a wrap for the prepend.
Are you still with me?
To create such wrap I need to set the content of the innerWrap to a string. But I must do it after if is executed. So I can use append, prepend or some other content object there. It does not really matter. I ended up on append.
As a result all four choices above are covered. This is what I love TypoScript and TYPO3 for: you can do almost everything with pure TypoScript!
Can this TypoScript be optimized or written in some other way? Feel free to comment and improve it!

4 comments:

  1. Realy nice demonstration.

    It makes me read TSRef stdWrap once again!

    ReplyDelete
  2. Nice solution ! I was testing other solution, but yours is better !



    Thanks

    ReplyDelete
  3. A tips for tt_news (single view) :



    [globalVar = GP:tx_ttnews|tt_news > 0]

    page.meta.keywords.prepend.data = register:newsKeywords

    [GLOBAL]

    ReplyDelete
  4. page {

    meta {

    keywords {

    prepend {

    data = levelfield: -1,keywords,slide

    }

    }

    }

    }

    ReplyDelete