Reason #6 for Choosing TYPO3: Custom Content Elements and ExtBase Again! (Part 2/3)
In my previous post, I covered how to customize the new content wizard and showed you a preview of the kind of interface I'm trying to accomplish in this tutorial. In this post, I'll show you how to render content elements using extBase and Fluid. This approach is still rough and while we're aiming to use it on a production site, I envision us refining and simplifying the approach over time. Also, please be aware that the kind of work I'm outlining in this post can break a site. Be responsible: don't do this on a live, production site.
Enough throat-clearing! Let's get going. As I mentioned in the last post, we're going to try to create a content element that looks like this:
The content element should be rendered from a clean, simple interface that looks like this:
Because this record is a tt_content record, we want to use as many of the available fields on the tt_content record as possible. Type, header, and text are all standard fields on the tt_content record. There is one additional field, however, and that is box color. In general, I don't recommend adding a bunch of additional fields to tt_content, but adding one or two won't hurt and it's not, in my view, inappropriate to add a new tt_content field for a new content element type, since that's where TYPO3 stores data about content.
Step 1: Kickstart Extension
To start things off, let's kickstart an extension. I'm going to set my extension key to clientcontent. You can choose your own extension key if you like; just be sure to change every instance of clientcontent in the code examples to your extension key. Once you've entered your extension key, press update to save it. Then add some general info to your extension in the kickstarter and set the type to frontend plug-in. When you're finished, it should look like this:
Save the form by pressing update and then click on the plus next to extend existing tables. We're going to add our box_color field to the tt_content table now. If you've used the extension kickstarter in the past, this ought to be straightforward. Go ahead and configure the field as a select field with a couple of color options, as shown in the screen shot:
The last thing we need to create in the kickstarter is a static Typoscript template. We could do all this by hand, of course, but the kickstarter speeds things up a bit. Go ahead and make a new static template. I called mine "Client Content Static Template." Be sure to enter some Typoscript scaffolding in the setup field or else the kickstarter won't output the Typoscript files. When you're done, your screen should look, more or less, like this:
Finally, we need to save our extension and write it to the file system. Click on the "view results" button and then on the "write" button. Wallah! You just made a TYPO3 extension. Be sure to install the extension in the extension manager and make sure that TYPO3 adds the new box_color field to the database.
Step 2: Configure the Content Elements and the Back-end Interface
In this step, we will add the configuration necessary to add our custom content elements to the list of content elements in the type field on content records in the TYPO3 backend. Our content record won't work on the front-end yet, but we'll at least be able to place it on the page.
If you've followed the steps so far, there should be a folder called clientcontent in /path/to/site/typo3conf/ext. This folder is the extension folder and it contains everything this extension needs to do its job. Using whatever tool you prefer, open up the ext_tables.php file. It should look more or less like this:
I've commented each line so that readers who are less familiar with TYPO3 extension development will have a better sense of what's going on here and what each line does. We need to make some changes to this, however, for usability purposes. First off, go ahead and remove or comment out the line that begins with
_t3lib_extMgm::addToAllTCAtypes_. Our new box color field is only relevant to our specific content element, so there's no need to spam every content element with this field.
Now, we're going to add a couple lines to this file. The purpose of these two lines is to tell TYPO3 to include our plugin as a content element in the backend as well as what fields to display on the element. Add these lines (be sure not to add the PHP tags—they are in the snippet so Github knows what syntax highlighting to use) before the closing php tag in the ext_tables.php file:
The first line does exactly what it says it does; it adds our plugin to TYPO3. The first argument,"Main Content Area Callout," is what will show up in the list of content types in the type field (see the first image in this post). The second argument is the value that will be placed in the type field of the tt_content record. This value will be used to key our extBase plugin as well. The third value tells TYPO3 to add the plugin as a CType (content type) rather than as a plugin. In my experience, clients get confused when they have to select a content type of plug-in and then select the plugin type from the plugin list. Too many steps!
The second line is fairly straight forward as well. In this case, we're taking advantage of TYPO3's type field functionality to tell it which fields to show when the user sets the content record to our custom content type. In this case, we've told it to show the type field itself, the header, the box_color field we added above, and the bodytext field with the richtext editor enabled. The syntax here is cryptic, but it's documented here. One really awesome thing about this approach is that you can use this line to change the title of fields in the backend. So, for example, we might include something like this:
The difference here is subtle but significant. Notice how I've added two labels into the array ("Callout Header" and "Callout Content"). With this approach, we can re-purpose fields on the tt_content record for our own purposes. For example, we might want to use the subheader field to store a CSS class that we'll insert into the rendered content. With this approach we could easily change the name of the field to "CSS Class" for our custom content element and then render that field down the road in Extbase.
I can hear the purists among you moaning and groaning about this approach. Yes, it's ugly—in a perfect world, we would use the header field ONLY for headers and the subheader field ONLY for subheaders. However, the TYPO3 tt_content table is anything but a perfect world, and until that future day when TYPO3 5 has arrived and we no longer have to fit all of our content records into one giant table, we're made to work with what we have. Moreover, the TYPO3 core does this very thing often; fields in the table are used in different ways on different records, and I'd rather re-purpose an existing field than unnecessarily add a new one.
Anyhow, no more digressions. If you've followed these steps, you should now have an ext_tables.php file that looks like this:
You should also now see a corresponding interface in the backend, one that's clean and lean:
Go ahead and enter some content, put this on a page, and view it in the frontend. You should see a warning telling you that TYPO3 doesn't know how to render this content element, which makes sense because we haven't yet told it how. This brings us to our next step.
Step 3: Tell TYPO3 to use our plug-in to render this content type
For this step, we're going to need to add a file called ext_localconf.php to our extension directory. If you don't know what ext_tables.php and ext_localconf.php files are for, take a moment to brush up on them here. Go ahead and create the ext_localconf.php file and add the following to it. Take a moment to read the comments in the code to make sure you understand what's happening in this file:
The last couple lines of this file are a bit of a hack. One of these days, Jochen Rau and company will, I'm sure, decide to add support for CTypes in Extbase, as it wouldn't be hard to do and it would make this sort of thing easier. Until then, we will just copy the Typoscript generated by ExtBase (at tt_content.list.20...) to the place we need it to be for our custom content element.
If you've setup ext_tables.php and ext_localconf.php correctly, you should now be able to view a page in the frontend.If you've done everything right, you should see an error. This is, believe it or not, a good thing, since it means that TYPO3 is trying to call an ExtBase controller when it renders our content element.
Step 4: Build out the ExtBase Controller and Template
Begin by creating the directory structure and files shown in the image below. We're going to keep it simple for now.
Notice that we've created the Classes folder and the Resources folder. Because this is such a simple plug-in, we don't even need a model at this point. All we really have here is the controller and the HTML template. Open up the ClientContentController file and add the following to it:
Now, open up the callout.html template and put some placeholder content in it so we know everything is working:
Take another look at the frontend and—fingers crossed—with luck we will now be able to see our fluid template being rendered. It's working for me, and it looks like this:
This is really just the beginning, because now we have done all the heavy lifting and from here things get much easier. Once we have this ExtBase framework, we can roll out additional custom content elements with very little work by adding new templates and actions.
Because this tutorial is running longer than I expected, I'm afraid you're going to have to wait for Part 3, in which I show you how to fully leverage the content record in Extbase using Fluid view helpers and Typoscript. Stay Tuned! More to come next week!
Let me know if anything doesn't work or if my instructions don't make sense and I'll update this post.
Update - 11/5/10:
I've uploaded the clientcontent extension, which contains the code samples in the tutorial above. It's a .t3x file, so you can install it via the extension manager. Click here to download the extension. Let me know how it goes!