Generating Dynamic Content for a Magento Module

Posted by Gabriel Somoza & filed under Magento.

Serving dynamic content can be very useful, regardless of programming language or platform. In my personal experience the technique becomes particularly handy when I need to supply certain configurable information to a script.

The following example shows how to achieve that in Magento. Its a common practice between Magento extension developers, especially for those extensions that are heavy on JavaScript.

1. Some Conventions

I assume we all know the basics of how to create a module so I won’t stop on many details on that topic. There some interesting articles here and there about how to do this.

I won’t use the usual “YourCompany/YourModule” approach throughout this article because I (personally) don’t like it so much. The word “Model” seems redundant when naming a module and early in my learning process it only confused me when used inside PHP or XML code, specially in the context of Magento or Zend. So instead, we’ll create a module named “Dynamic” under namespace “Acme“.

Last but not least I’m going to place some files under the ‘default/default’ package/theme. If you’re using another package or theme I assume you know what you’re doing there as well.

2. Configuration File

The configuration file sets up your module for use in Magento. Among a few other things, here’s where we will build our route. Our goal is to retrieve the generated javascript from the following URL: website.com/dynamic/js .

app/code/local/Acme/Dynamic/etc/config.xml (click to download a clean version)

<!--?xml version="1.0?-->
<config>
    <modules><!-- basic information about the module -->
        <Acme_Dynamic>
            <version>0.1.0</version>
        </Acme_Dynamic>
    </modules>
    <frontend>
        <routers> <!-- use this section to build routes (i.e., URLs) -->
            <!-- build our routes here -->
            <dynamic> <!-- router namespace - module name should be used, as a 
                           good practice -->
                <!-- setup a standard router for this route -->
                <use>standard</use>
                <args>
                     <!-- search for classes starting with "Acme_Dynamic_" -->
                    <module>Acme_Dynamic</module>
                    <!-- 'frontName' builds the route: 
                            website.com/[frontName]/[action]/[params] -->
                    <frontName>dynamic</frontName> 
                    <!-- the generated route is: 
                            website.com/dynamic/[action]/[params] -->
                </args>
            </dynamic>
        </routers>
        <layout> <!-- use this section to specify layout files -->
            <updates> <!-- we're going to include layout updates -->
                <dynamic> <!-- layout update namespace, same as with router -->
                    <!-- we can give any name to the file, but good practice is 
                         to use "[namespace]-[module].xml" -->
                    <file>acme-dynamic.xml</file>
                    <!-- the file will be located at:
                         app/design/frontend/default/default/layout/ -->
                </dynamic>
            </updates>
        </layout>
    </frontend>
</config>

3. The Controller

We are going to serve JavaScript under the ‘index’ action in this controller.

app/code/local/Acme/Dynamic/controllers/JsController.php

<?php
class Acme_Dynamic_JsController extends Mage_Core_Controller_Front_Action {
    /*
     * Index action
     * This function enables the following route:
     *    //www.website.com/dynamic/js/index
     * Since 'index' is the default action for the controller, 
     * the following route is also equivalent:
     *    //www.website.com/dynamic/js
     */
    public function indexAction() {
        // Set the appropriate content-type
        $this->getResponse()->setHeader('Content-type', 'text/javascript');
        // Loads and renders the layout file we will create soon
        $this->loadLayout();
        $this->renderLayout();
    }
    
    /*
     * We could declare other actions here by using the format
     *    public function [name]Action()
     * which will map to the routes in the form:
     *    //www.website.com/dynamic/js/[name]
     */
}

4. The Layout File

Just like we specified on line 31 of config.xml we’re going to use a layout file to configure exactly what we want the index to return (i.e., the JavaScript).

app/design/frontend/default/default/layout/acme-dynamic.xml

<?xml version="1.0"?>
<!-- Configure the layout for the 'index' action created above -->
<layout version="0.1.0">
    <!-- Note how the following tag goes: [namespace]_[module]_[controller]_[action]
         You can repeat the same pattern for any number of actions. -->
    <acme_dynamic_js_index>
        <reference name="root"> <!-- reference the root block of the layout -->
            <!-- The 'setTemplate' action configures which file will be rendered 
                 with the referenced block, which in this case is the 'root' block -->
            <action method="setTemplate"><template>acme/dynamic/js.phtml</template></action>
            <!-- So the 'index' action will render the template file located at 
                 '.app/design/frontend/default/default/template/acme/dynamic/js.phtml -->
        </reference>
    </acme_dynamic_js_index>
</layout>

5. The Template File

This is where it all makes sense, hopefully. The file will be rendered with the correct content-type and interpreted by the browser as JavaScript.

app/design/frontend/default/default/template/acme/dynamic/js.phtml

<?php
/*
 * Use this file to generate your JS magic, just as you would an HTML page. For example:
 */
$_product = Mage::getModel('catalog/product')->load(27); // for the sake of the example
?>
jQuery(document).ready(function($){
    $('#featured').html('Featured Product: <?php echo $_product->getName() ?>');
});

6. Activate the Module

A small but important step. Further explanation would fall out of scope so I’ll just provide the link to a file you can use to activate this module.

app/etc/modules/Acme_Dynamic.xml

Conclusion + Resources

That’s it! You can actually generate any kind of file with this method, including images and PDFs.

I made a compressed version of the entire module available here. You can also view the source online as a Github Gist.

If you liked this article please leave comment or share it!

Leave a Reply