I have a module that processes web forms and uses a template to generate an email when finished.

Here is the module code:

$data['message'] = $message;
$this->EE->load->library('Template', NULL, 'TMPL');
$this->EE->TMPL->depth = 1;
$this->EE->TMPL->fetch_and_parse('experience', '_email');
$this->EE->TMPL->depth = 0;
$html_message = $this->EE->TMPL->parse_globals($this->EE->TMPL->final_template);
$html_message = $this->EE->TMPL->parse_variables_row($html_message, $data);

In the template, I want to take advantage of the new Markdown formatting, so there is this bit in the experience/_email template:

    <td style="padding:15px 20px;color:#333;line-height:1.25em;font:13px Tahoma, Verdana, Arial, Helvetica, sans-serif;" class="body" colspan="2" bgcolor="#ffffff" valign="top" align="left">

However, {message} does NOT get converted from Markdown to HTML. I suspect it's something to do with either the order of operations or how template parsing works? Does anyone know why this fails?

Here is a more detailed flow. There is a template_group/template page visited. In that template is the form. The template is entirely encapsulated with a module call:

{exp:custom_module:workshop identifier="{last_segment}"}
    {exp:channel:entries channel="workshops" limit="1" sort="asc"}
        {embed="modules/_header" page_title="{categories show_group="6"}{category_name} - {/categories}Workshop Registration" body-class="pd"}
        <div class="content">...

The module then has the correlating method:

public function workshop()
    $identifier = $this->EE->TMPL->fetch_param('identifier');

    if ($all_of_the_form_data_passes) {
        // send an email and redirect to the thank you page.
        $this->EE->email->mailtype = 'html';
        $this->EE->email->from('[email protected]');
        $this->EE->email->to($user['name_first'] . ' ' . $user['name_last'] . '<' . $user['email'] . '>');
        if ($bcc_recipients)


        $data['message'] = $message;
        $this->EE->load->library('Template', NULL, 'TMPL');
        $this->EE->TMPL->depth = 1;
        $this->EE->TMPL->fetch_and_parse('experience', '_email');
        $this->EE->TMPL->depth = 0;
        $html_message = $this->EE->TMPL->parse_globals($this->EE->TMPL->final_template);
        $html_message = $this->EE->TMPL->parse_variables_row($html_message, $data);

    // If anything didn't go well, finish loading the originally requested template_group/template with error messages embedded (in $data)
    return $this->EE->TMPL->parse_variables_row($this->EE->TMPL->tagdata, $data);

So there's two templates involved in the process. The template the user visits that renders the form. In the method for the module wrapping that template, the form data is analyzed and if it went well, a second template is fetched, parsed and emailed. If anything did NOT go well, the original template is parsed, supplied with error messages and returned to the user.

I've now just worked around the issue by declaring the formatting type in the $data array in the module method as follows:

$data['message'] = array(
    $message, array(
        'text_format' => 'markdown',
        'html_format' => 'markdown'

(as shown in the Template Class instructions.)

I've also just found the Typography Class (not enough reputation points to link to it, but it's part of the EE manual), which let's me do raw formatting in the module:

$data['message'] = ee()->typography->markdown($message);

Here is now a third solution to the problem, found in this post. Instead of using fetch_and_parse in one command, separate them, as the parse step is evaluating the exp:markdown before the {message} is getting injected. So, I did it as follows:

ee()->TMPL->depth = 1; // Need to increase the depth to get the hidden template
$email_template = ee()->TMPL->fetch_template('experience', '_email', FALSE, ee()->config->item('site_id')); // Fetch ONLY. We want the variables replaced before doing the final parse.
ee()->TMPL->depth = 0; // Cleaning up
$html_message = ee()->TMPL->parse_variables_row($email_template, $data); // Parse $data
ee()->TMPL->parse($html_message, FALSE, ee()->config->item('site_id')); // Finish up by parsing EE tags.

However, none of those tags are in the documentation. I feel like I'm using Private APIs for lack of a better description. Is this the properly sanctioned way of doing this, or is there a way to use parse="inward" to get this to work properly without this?

  • I need the module which loads {message}. Is something like {exp:workshop}[...]<tr><td>{exp:markdown}{message}{/exp:markdown}</td></tr>[...]{/exp:workshop}?
    – Sobral
    Commented Jan 10, 2014 at 2:50
  • It's all above. {message} is set with $data['message']. And then, the email template is fetched and parsed with $this->EE->TMPL->fetch_and_parse('experience', '_email'); through to $html_message = $this->EE->TMPL->parse_variables_row($html_message, $data);
    – jaydisc
    Commented Jan 10, 2014 at 4:43
  • Are you trying to use one of these?
    – Sobral
    Commented Jan 10, 2014 at 11:21
  • No. The page is basically an event registration form. Upon successful registration, a separate email template is loaded and emailed to the customer.
    – jaydisc
    Commented Jan 12, 2014 at 7:28
  • I'm sorry, man, but I still don't get how the {message} variable is being parsed. Do you mind of show me your full template?
    – Sobral
    Commented Jan 12, 2014 at 14:31

1 Answer 1


You should set the parameter parse to inward in you module opening tag, so the {exp:markdown} will wait for the {message} variable be ready.

If you show you module tags, I can write a sample code.

  • Thank you. I've added some extra code. I'm not sure if it's what you're looking for. The template that calls the module is not the template I'm having trouble parsing. It's the email template I'm grabbing afterward that isn't parsing.
    – jaydisc
    Commented Jan 10, 2014 at 1:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.