Formatting Channel Entries as JSON in ExpressionEngine

If you are working with javascript a lot in ExpressionEngine, you will probably at some point need to use AJAX. Libraries such as jQuery make this easy, and out of the box it’s possible to create simple ExpressionEngine templates which can return HTML to be consumed by your javascript code. However, it is sometimes more convenient to return JSON data which can then be formatted client-side using javascript.

Producing JSON with ExpressionEngine is not so straightforward. There is a plugin for ExpressionEngine which produce JSON formatted output but this offers no customisation over the output, which is especially important if using complex custom fields (such as Channel Files or Channel Images).

Basic JSON

The solution is to create the formatted JSON yourself using standard ExpressionEngine templates. Below is a simple example of a channel entry formatted as JSON. The basic form of JSON is that each object should consist of a series of name-value pairs, with each pair separated by a comma, with the whole object surrounded by braces.

  {
    "Title": "Test Blog Post",
    "Link": "http://www.mysite.com/blog/view/test-blog-post/",
    "Summary": "This is the summary of my blog post",
    "Category": "Test Posts",
    "Image": "<img width=\"100\" height=\"100\" alt=\"Image Description\" title=\"Image Title\" src=\"http://www.mysite.com/images/test-blog-post-image.png\">"
  }

Notice that any double-quotes in the values have to be escaped with a forward-slash to ensure they can be interpreted correctly in javascript.

If you have multiple objects (i.e. an array), each object should be separated by a comma and the whole array should be enclosed in square brackets.

[
  {
    "Title": "Test Blog Post",
    "Link": "http://www.mysite.com/blog/view/test-blog-post/",
    "Summary": "This is the summary of my blog post",
    "Category": "Test Posts",
    "Image": "<img width=\"100\" height=\"100\" alt=\"Image Description\" title=\"Image Title\" src=\"http://www.mysite.com/images/test-blog-post-image.png\">"
  },
  {
    "Title": "Test Blog Post 2",
    "Link": "http://www.mysite.com/blog/view/test-blog-post2/",
    "Summary": "This is the summary of my blog post 2",
    "Category": "Test Posts",
    "Image": "<img width=\"100\" height=\"100\" alt=\"Image Description\" title=\"Image Title\" src=\"http://www.mysite.com/images/test-blog-post2-image.png\">"
  }
]

Producing JSON with ExpressionEngine

So, that’s the basic form of JSON, how can we produce this in ExpressionEngine using templates? Here is an example which does just that.

[
    {exp:channel:entries channel="blog" limit="100" backspace="6"}
    {
        "Title": "{title}",
        "Link": "{title_permalink="blog/view"}",
        "Summary": "{if summary}{summary}{/if}",
        "Category": "{categories limit="1"}{category_name}{/categories}",
        "Image": "{exp:channel_images:images entry_id="{entry_id}" limit="1"}<img width=\"{image:width}\" height=\"{image:height}\" alt=\"{image:description}\" title=\"{image:title}\" src=\"{image:url}\">{/exp:channel_images:images}"
    },
    {/exp:channel:entries}
]

All we are doing here is injecting into a simple JSON template the channel tags to produce the output required. As you can see, we can format the channel tags however we want, including using conditionals, nest tags etc.

Producing JSON with ExpressionEngine Correctly

There’s just one problem with the template above. We’ve already stated above that any double-quotes in the JSON object values need to be escaped to ensure that we don’t break the formatting of the output. However, we cannot be sure what values will be within the individual channel entries. We therefore need to act defensively and remove/escape any characters which might cause problems. Luckily for us, that nice man Low has provided the excellent Low Replace plugin which allows us to perform find and replace operations on any tag prior to display.

In this case, we want to prefix double-quotes with a backslash, and also also remove any linebreaks as then can also destroy the formatting.

[
    {exp:channel:entries channel="blog" limit="100" backspace="6"}
    {
        "Title": "{exp:low_replace find="QUOTE|NEWLINE" replace="\QUOTE|SPACE" multiple="yes"}{title}{/exp:low_replace}",
        "Link": "{title_permalink="blog/view"}",
        "Summary": "{if summary}{exp:low_replace find="QUOTE|NEWLINE" replace="\QUOTE|SPACE" multiple="yes"}{summary}{/exp:low_replace}{/if}",
        "Category": "{categories limit="1"}{exp:low_replace find="QUOTE|NEWLINE" replace="\QUOTE|SPACE" multiple="yes"}{category_name}{/exp:low_replace}{/categories}",
        "Image": "{exp:channel_images:images entry_id="{entry_id}" limit="1"}<img width=\"{image:width}\" height=\"{image:height}\" alt=\"{image:description}\" title=\"{image:title}\" src=\"{image:url}\">{/exp:channel_images:images}"
    },
    {/exp:channel:entries}
]

And you’re done. >Once you’ve completed your JSON, you might want to check that the JSON produced is valid (because if it isn’t valid your jQuery will typically fail silently). For this, I use the excellent JSLint online validator.

05
Jan 2012
POSTED BY
POSTED IN ExpressionEngine
DISCUSSION 7 Comments
TAGS

Don’t forget your XID!

Having just spent over an hour trying to work out why my Module Control Panel forms weren’t submitting correctly, I thought I’d document the fix here (for my purposes and yours).

The error I was seeing was that when submitting my control panel form, rather than posting to my module function, the form was redirecting back to the ExpressionEngine control panel homepage. The reason for this? I had forgotten to include the XID secure form hidden post variable.

Wrong

<form method="post" action="<?=$base_url?>&amp;method=save">
...blah
<input type="submit" name="Save"/>
</form>

Right

<form method="post" action="<?=$base_url?>&amp;method=save">
<input type="hidden" name="XID" value="<?=XID_SECURE_HASH?>" />
blah
<input type="submit" name="Save"/>
</form>
19
Dec 2011
POSTED BY
POSTED IN ExpressionEngine
DISCUSSION 3 Comments
TAGS

Using jQueryUI features in your ExpressionEngine Control Panel

Sometimes you might find it useful to add some additional UI features to your EE control panel pages – luckily EE comes bundled with jQuery and jQueryUI so you can use any of the jQuery UI widgets without needing to bundle the scripts themselves. In this example, I’m going to add a nice Date Picker control to a form to make it easier for users to enter dates.

To begin with, we need to tell EE to include the necessary jquery UI features. jQueryUI is modular and has dependencies, so even though I only want to use the ‘datepicker’ feature, that in turn relies on the ‘core’ library so I need to include them both in the list of required modules. This code will need to be in your control panel function prior to loading your view

$this->EE->cp->add_js_script(
array('ui' => array(
'core', 'datepicker'
)
));

And then in your view, it’s the usual jQuery code to wire it up. In this case I’m going to declare that any input field with a class of “datepicker” should be converted into a jQueryUI datepicker field.

<script type="text/javascript">
    $(function() {

        $("input.datepicker").datepicker();

    });
</script>

<form method="post">

<input id="expiry_date" class="medium datepicker" type="text" name="expiry_date" value="<?=htmlspecialchars($expiry_date)?>" />

<input class="submit" type="submit" value="<?=lang('submit')?>" />

</form>

You can of course do the same for any other jQuery UI feature which means it’s easy to add great interactive features to your control panel forms

08
Dec 2011
POSTED BY
DISCUSSION 2 Comments
TAGS

Using ExpressionEngine Actions with AJAX

ExpressionEngine Actions are lightweight hooks in EE which allow you to register a class & method to be called on a specific URL regardless of the templates or urls which have been configured on the user’s site.

Actions are a great way for your plugin to handle AJAX requests because your EE module can register an action and then call that action from the client using jQuery or similar. However, there are a couple of caveats which you need to be aware of

In my particular case, the fact that the template engine is not loaded is a major problem because I want to return some HTML back to client – HTML which has been generated from an EE template.

Firstly, I need to make sure that the template library is loaded, and if it isn’t I need to load it manually.

class My_module {

    function __construct() {

        $this->EE =& get_instance();

        // --------------------------------------
        // Make sure the template library is loaded
        // It isn't by default when running as an action
        // --------------------------------------

        // Load EE Templates if it doesn't exist
        if ( ! class_exists('EE_Template'))
        {
	        $this->EE->TMPL =& load_class('Template', 'libraries', 'EE_');
        }
    }
}

The last thing to be aware of is that for action methods, you can’t just return your parsed template as you would in a normal module method. For example, a normal method might look like


function my_method() {

    ...

    $template  = $this->EE->functions->prep_conditionals($template, $conditionals);
    $template  = $this->EE->TMPL->parse_variables_row($template, $view_data);

    return $template;
}

However, for an action, you need to perform an extra parse step and then manually push the output to the browser.


function my_ajax_method() {

    ...

    $template  = $this->EE->functions->prep_conditionals($template, $conditionals);
    $template  = $this->EE->TMPL->parse_variables_row($template, $view_data);

    $this->EE->TMPL->parse($template);

    $this->EE->output->set_output($this->EE->TMPL->final_template);
}

Even better, if you are using JSON to return your data, you can utilise a built-in EE function to format your data. It also has the added benefit of automatically disabling the profiler.


function my_ajax_method() {

    ...

    $template  = $this->EE->functions->prep_conditionals($template, $conditionals);
    $template  = $this->EE->TMPL->parse_variables_row($template, $view_data);

    $this->EE->TMPL->parse($template);

    $data = array('html'    => $this->EE->TMPL->final_template,
                  'success' => true);

    $this->EE->output->send_ajax_response($data);
}
10
Nov 2011
POSTED BY
DISCUSSION 4 Comments
TAGS

When ExpressionEngine calls your class to execute an action, it passes a constructor argument of 0

In /system/expressionengine/libraries/Actions.php, you will find this code around line 185

    // Instantiate the class/method		
    $ACT = new $class(0);

Not sure why this is done, but if your class takes a constructor argument (like mine does) you may find yourself scratching your head at why it won’t load when called from an action.

09
Nov 2011
POSTED BY
POSTED IN ExpressionEngine PHP
DISCUSSION 1 Comment
TAGS

Using Partial Views in the ExpressionEngine Control Panel (for ajax requests or similar)

If you want to use ajax to populate certain parts of your Control Panel user interface in ExpressionEngine, you will find that you have a problem if you want to use the standard MVC framework included, because EE will wrap all your views with the control panel “frame” (html/images/css etc).

For example, the following view is intended to be returned as a partial view to be called using ajax, but it will instead be wrapped by the EE control panel


public function ajax_example()
{
	// --------------------------------------
	// Load view and return it
	// --------------------------------------
	
	$data = array('some_view_data' => 'Value');

	return $this->EE->load->view('ajax_example_view', $data, TRUE);
}

To fix this, all we have to do is grab the output from our view and spit it straight out to the browser without returning it to the calling function (which is where the frame is added).


public function ajax_example()
{
	// --------------------------------------
	// Load view and echo it
	// --------------------------------------

	$data = array('some_view_data' => 'Value');

	echo $this->EE->load->view('ajax_example_view', $data, TRUE);

	exit;
}

This works, but you do lose some functionality, such as seeing the output profiler and/or template debugger. However, we can fix this by using the EE/CI output class instead to display the view.


public function ajax_example()
{
	// --------------------------------------
	// Load view and display it
	// --------------------------------------

	$data = array('some_view_data' => 'Value');

	$response = $this->EE->load->view('ajax_example_view', $data, TRUE);

	$this->EE->output->set_output($response);
	$this->EE->output->_display();

	exit;
}

This works better, but we don’t always want to see the output profiler, especially on ajax requests because the profiler output could break the layout or, if we are returning JSON for example, can destroy the output totally. So, let’s wrap this up into a helper method with some optional parameters


public function ajax_example()
{
	// --------------------------------------
	// Load view and display it
	// --------------------------------------

	$data = array('some_view_data' => 'Value');

	$this->partial_view('ajax_example_view', $data);

}

private function partial_view($view_name, $data, $show_profiler = null) {

	$response = $this->EE->load->view($view_name, $data, TRUE);

	if(isset($show_profiler)) {
		$this->EE->output->enable_profiler($show_profiler);
	}

	$this->EE->output->set_output($response);
	this->EE->output->_display();

	exit;
}
08
Nov 2011
POSTED BY
DISCUSSION 2 Comments
TAGS

How to dynamically create url_titles with jQuery in ExpressionEngine modules

Whilst developing your custom module for EE, you might have a requirement to add a Url Title for one of your data types. ExpressionEngine does this in a few places in the control panel (for new Entries, Channels etc) so why not just reuse the existing functionality?

First, we need to load the ‘ee_url_title’ jQuery plugin which EllisLabs have kindly provided. The snippet below does this for you and needs to be included in your mcp file controller method.


$this->EE->cp->add_js_script('plugin', 'ee_url_title');

Now, we need to switch over to your view and add a little javascript. So given the following html code in your view


<label for="title"><?=lang('title')?></label>
<input type="text" name="title" id="title" value="<?=htmlspecialchars($title)?>" />

<label for="url_title"><?=lang('url_title')?></label></td>
<input type="text" name="url_title" id="url_title" value="<?=htmlspecialchars($url_title)?>" />

You only need to add the following snippet of javascript, this can either be in your view, or even better add it to a separate javascript file.

$(function() {

	// Attach url_title live feedback
	$("#title").bind("keyup blur",function(){
		$("#title").ee_url_title($("#url_title"));
	});

});
08
Nov 2011
POSTED BY
DISCUSSION 1 Comment
TAGS

“Disallowed Key Characters” response when sending ajax requests to ExpressionEngine control panel

When developing a new ExpressionEngine module which uses Ajax extensively within the control panel, I kept getting the following response when trying to access a control panel url.

Disallowed Key Characters.

The reason for this is the EE blocks any urls which contain anything other than the following

a-z
0-9 
:
_ 
/ 
-

The reason it was failing was because my urls contained escaped html characters – &amp; instead of &. The solution was to convert the escaped url back to unescaped by using the htmlspecialchars_decode() function

htmlspecialchars_decode($url)
08
Nov 2011
POSTED BY
POSTED IN ExpressionEngine PHP
DISCUSSION 0 Comments
TAGS