In reference to my other thread, I wanted to follow up with my solution for basic templating with Switch. Essentially, this will allow you to easily manage your HTML emails. So if you had, let's say, 20 different HTML emails and your boss tells you to swap out a logo, you can make the change in one place.
This system uses PHP and Twig (a templating library) to generate HTML which is then saved to .html files. You just run the PHP code once and it updates all of the files. If you make a change it will overwrite them with the same name, meaning you can use Git or some other method of version control to update everything -- and Switch will automatically pick up the changes without re-linking.
You'll need:
- PHP 5.2.4 or later
- Composer
- Twig
Setup
Download Composer using the manual download links. Put the composer.phar in your project directory.
Make a new text file called composer.json with the following contents:
{
"require": {
"twig/twig": "1.*"
}
}
Open up a command prompt. cd to your project directory and run php composer.phar install:
Now composer is going to do it's magic. Once it's complete, you are ready to use Twig.
Using Twig
Twig is a nice templating system written in PHP. I recommend you take a look at the documentation. Essentially, you can do loops, logic statements, including, and extending of template files. This is nice because we will want to include headers/footers or extend a base template. Here is how mine is setup:
In /views/ I created a directory called /Email/ which is the base theme path. There, I added a file called base.html.twig which has the HTML email I've decided to use. Within the main table HTML, I declare a block:
{% block body_cells %}
<td>Error! "body_cells" block not set.</td>
{% endblock %}
This block should always be overwritten when extended, so the default text should only be shown in the case that something goes wrong.
I then create two more templates, each "extending" base.html.twig
one_column.html.twig
{% extends 'Email/base.html.twig' %}
{% block body_cells %}
<td width="500" valign="top">
{% block column %}
{% endblock %}
</td>
{% endblock %}
two_column.html.twig
{% extends 'Email/base.html.twig' %}
{% block body_cells %}
<td valign="center" style="text-align:center;">
{% block left_column %}
{% endblock %}
</td>
<td width="250" valign="top" style="padding-left: 0;">
{% block right_column %}
{% endblock %}
</td>
{% endblock %}
Now we have a one column and a two column variant of the main template which inherits everything from base.html.twig.
Finally, we'll create the actual email -- complete with Switch variables. Going forward, this is all you have to make when you add a new email!
{% extends 'Email/two_column.html.twig' %}
{% block left_column %}
<img src="{{ dashboard_url }}/img/ico/misc/error.png">
<br>
Please contact the CSR who is CC'd on this email with any questions.
{% endblock %}
{% block right_column %}
<span style="font-size:16px;"><a href="#" target="_blank" style="color: #4d5fab; text-decoration: none;">[Job.PrivateData:Key=JobNumber] Proof CSR Rejection</a></span>
<br>
<span><i>Account: [Job.PrivateData:Key=CustomerName]</i></span>
<p>
Dear Prepress team,<br>
The CSR for this job has rejected a proof prior to it being sent to a client. Please address the CSR's concerns and drop a new proof into the proofing workflow as you did before.
<br><br>
<strong>Comments:</strong>
[Metadata.Text:Path="/field-list/field[1]/field-list/field/value",Dataset="Check",Model="XML"]
<br><br>
Description: [Job.PrivateData:Key=JobDescription]
</p>
{% endblock %}
You'll see that this email extends two_column.html.twig which in turn extends base.html.twig. Cool, huh?
Lastly, we need an app page to execute the code and make the files. Here is the quick and dirty page I have for now:
<?php
// Autoload
require_once '../vendor/autoload.php';
// Init twig
$loader = new Twig_Loader_Filesystem('../views/');
$twig = new Twig_Environment($loader);
// Need this for my template
$dashboard_url = 'https://uri.com';
// Render email and save to a variable
$problem_csr = $twig->render('Proof/problem_csr.html.twig', array('dashboard_url' => $dashboard_url));
// Function for outputting html files
function outputHtml($input, $fileNameProper)
{
$output_dir = '../build/';
$finalFilePath = $output_dir.$fileNameProper.'.html';
file_put_contents($finalFilePath, $input);
}
// Output
outputHtml($problem_csr, 'problem_csr');
Now loading app.php runs the code and outputs the HTML for each template and saves it to a .html file. Here is a screenshot of the HTML when run in a web browser so you can get an idea:
Now you can throw this in a Git repo and sync it with your Switch server. In the future, if you had to make a change to the email templates, you would just update base.html.twig, run app.php again, then commit to Git. Then, you would pull the commit on your Switch server and you've just updated every single email with your template change.
Twig templating with Switch HTML Emails
Twig templating with Switch HTML Emails
Chat: open-automation @ gitter
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
-
- Advanced member
- Posts: 230
- Joined: Thu Aug 07, 2014 10:04 am
Twig templating with Switch HTML Emails
Very impressive!
Will try to get into it
Thank you, Gabriel
Will try to get into it
Thank you, Gabriel
Twig templating with Switch HTML Emails
I've converted all of my emails over to this templating method and I have to say, it's much easier to work with.
Here's an updated app.php page. This way, you just have to add a new element to $emails (lines 13-22) to add a new email to the list of what is generated:
<?php
// Autoload
require_once '../vendor/autoload.php';
// Init twig
$loader = new Twig_Loader_Filesystem('../views/');
$twig = new Twig_Environment($loader);
// Need this for my template
$dashboard_url = 'https://client.shawmutdelivers.com';
// Register emails which are generated
$emails = new stdClass();
$emails->proof_problem_csr = 'Proof/problem_csr.html.twig';
$emails->proof_problem_mailing = 'Proof/problem_mailing.html.twig';
$emails->proof_new_mailing = 'Proof/new_mailing.html.twig';
$emails->proof_new_csr = 'Proof/new_csr.html.twig';
$emails->proof_problem_client = 'Proof/problem_client.html.twig';
$emails->proof_approved_client = 'Proof/problem_client.html.twig';
$emails->proof_notify_client = 'Proof/approved_client_web.html.twig';
$emails->proof_error_jobnumber_not_found = 'Proof/error_jobnumber_not_found.html.twig';
$emails->proof_notify_shipper_hard_copy = 'Proof/notify_shipper_hard_copy.html.twig';
// Function for rendering and outputting html files
function outputHtml($twig, $template, $name, $parameters)
{
// Render in Twig
$rendered = $twig->render($template, $parameters);
// Build paths
$output_dir = '../build/';
$finalFilePath = $output_dir.$name.'.html';
// Check if file exists
if(file_exists($finalFilePath)){
$existingContents = file_get_contents($finalFilePath);
// Compare to new
if($existingContents == $rendered) return false;
}
// Write out if something changed
file_put_contents($finalFilePath, $rendered);
return true;
}
// Output action
foreach($emails as $name => $template)
{
$parameters = array();
$parameters['dashboard_url'] = $dashboard_url;
$outputResult = outputHtml($twig, $template, $name, $parameters);
if($outputResult){
echo "Built: '$name.html'<hr>";
} else {
echo "No change to '$template'<hr>";
}
}
Now when you run app.php, it will build any templates which have changed since the last revision, and will let you know which ones weren't updated:
Here's an updated app.php page. This way, you just have to add a new element to $emails (lines 13-22) to add a new email to the list of what is generated:
<?php
// Autoload
require_once '../vendor/autoload.php';
// Init twig
$loader = new Twig_Loader_Filesystem('../views/');
$twig = new Twig_Environment($loader);
// Need this for my template
$dashboard_url = 'https://client.shawmutdelivers.com';
// Register emails which are generated
$emails = new stdClass();
$emails->proof_problem_csr = 'Proof/problem_csr.html.twig';
$emails->proof_problem_mailing = 'Proof/problem_mailing.html.twig';
$emails->proof_new_mailing = 'Proof/new_mailing.html.twig';
$emails->proof_new_csr = 'Proof/new_csr.html.twig';
$emails->proof_problem_client = 'Proof/problem_client.html.twig';
$emails->proof_approved_client = 'Proof/problem_client.html.twig';
$emails->proof_notify_client = 'Proof/approved_client_web.html.twig';
$emails->proof_error_jobnumber_not_found = 'Proof/error_jobnumber_not_found.html.twig';
$emails->proof_notify_shipper_hard_copy = 'Proof/notify_shipper_hard_copy.html.twig';
// Function for rendering and outputting html files
function outputHtml($twig, $template, $name, $parameters)
{
// Render in Twig
$rendered = $twig->render($template, $parameters);
// Build paths
$output_dir = '../build/';
$finalFilePath = $output_dir.$name.'.html';
// Check if file exists
if(file_exists($finalFilePath)){
$existingContents = file_get_contents($finalFilePath);
// Compare to new
if($existingContents == $rendered) return false;
}
// Write out if something changed
file_put_contents($finalFilePath, $rendered);
return true;
}
// Output action
foreach($emails as $name => $template)
{
$parameters = array();
$parameters['dashboard_url'] = $dashboard_url;
$outputResult = outputHtml($twig, $template, $name, $parameters);
if($outputResult){
echo "Built: '$name.html'<hr>";
} else {
echo "No change to '$template'<hr>";
}
}
Now when you run app.php, it will build any templates which have changed since the last revision, and will let you know which ones weren't updated:
Chat: open-automation @ gitter
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Twig templating with Switch HTML Emails
Made another update today by porting over to Silex. I'll make a repo of the bones of this at some point. I've become pretty reliant on this method of templating. Managing email templates any other way with a growing number of flows seems unmanagable.
Update composer.json
{
"require": {
"silex/silex": "~1.1",
"twig/twig": "1.*",
"twig/extensions": "*"
}
}
Then, run php composer.phar update
Updated app.php
<?php
// Autoload
require_once '../vendor/autoload.php';
$app = new SilexApplication();
$app['debug'] = true;
// Init twig
$loader = new Twig_Loader_Filesystem('../views/');
$twig = new Twig_Environment($loader, array('debug' => true));
$twig->addExtension(new Twig_Extension_Debug());
// Need this for my template
$dashboard_url = 'https://XXX.com';
// Register emails which are generated
$emails = new stdClass();
// Proofs
$emails->proof_problem_csr = 'Proof/problem_csr.html.twig';
$emails->proof_problem_mailing = 'Proof/problem_mailing.html.twig';
$emails->proof_new_mailing = 'Proof/new_mailing.html.twig';
$emails->proof_new_csr = 'Proof/new_csr.html.twig';
$emails->proof_problem_client = 'Proof/problem_client.html.twig';
$emails->proof_approved_client = 'Proof/problem_client.html.twig';
$emails->proof_notify_client = 'Proof/approved_client_web.html.twig';
$emails->proof_error_jobnumber_not_found = 'Proof/error_jobnumber_not_found.html.twig';
$emails->proof_notify_shipper_hard_copy = 'Proof/notify_shipper_hard_copy.html.twig';
// File Transfer
$emails->filetransfer_new_csr = 'FileTransfer/new_csr.html.twig';
$emails->filetransfer_new_unknown = 'FileTransfer/new_unknown.html.twig';
// Virtual Prepress
$emails->preflight_ready_csr = 'VirtualPrepress/preflight_ready_csr.html.twig';
// Function for rendering and outputting html files
function outputHtml($twig, $template, $name, $parameters)
{
// Render in Twig
$rendered = $twig->render($template, $parameters);
// Build paths
$output_dir = '../build/';
$finalFilePath = $output_dir.$name.'.html';
// Build return object
$return = new stdClass();
$return->name = $name;
$return->template = $template;
$return->build_path = $finalFilePath;
$return->type = 'updated';
// Check if file exists
if(file_exists($finalFilePath)){
// Get original filesize
$return->size = round(filesize($finalFilePath)/1024);
// Get the existing
$existingContents = file_get_contents($finalFilePath);
// Compare to new
if($existingContents == $rendered){
$return->type = 'no_change';
return $return;
};
} else {
$return->type = 'new';
}
// Write out if something changed
file_put_contents($finalFilePath, $rendered);
// Get updated filesize
$return->size = round(filesize($finalFilePath)/1024);
// Send successful return if a change was made
return $return;
}
$app->get('/', function () use ($emails, $dashboard_url, $twig) {
// Output action
$totalOutputResults = array();
foreach($emails as $name => $template)
{
$parameters = array();
$parameters['dashboard_url'] = $dashboard_url;
$outputResult = outputHtml($twig, $template, $name, $parameters);
array_push($totalOutputResults, $outputResult);
}
// Render in Twig
$rendered = $twig->render('Default/compile.html.twig', array("total_output_results" => $totalOutputResults));
return $rendered;
});
// Run the app
$app->run();
Defaultcompile.html.twig
{% extends 'base.html.twig' %}
{% block body %}
<div class="row">
<div class="col-md-4">
<h3>Emails</h3>
<div class="list-group">
{% for result in total_output_results %}
<a href="../{{ result.build_path }}" target="_blank" class="list-group-item {% spaceless %}
{% if result.type == 'new' %}list-group-item-success{% elseif result.type == 'updated' %}list-group-item-warning{% endif %}
{% endspaceless %}">
{% if result.type == 'new' %}<i class="fa fa-star-o"></i>{% elseif result.type == 'updated' %}<i class="fa fa-pencil-square-o"></i>{% else %}<i class="fa fa-circle-o"></i>{% endif %}
{{ result.name }}
<span class="badge pull-right">{{ result.size }} KB</span>
</a>
{% endfor %}
</div>
</div>
<div class="col-md-4">
<h3>Options</h3>
<a href="{{ app.request.uri }}" class="btn btn-default btn-lg"><i class="fa fa-refresh"></i> Rebuild</a>
</div>
</div>
{% endblock %}
Now the app will generate and in a nice way, display which templates have changed or are new. Each entry in the list is a link which brings you to the compiled html template.
Update composer.json
{
"require": {
"silex/silex": "~1.1",
"twig/twig": "1.*",
"twig/extensions": "*"
}
}
Then, run php composer.phar update
Updated app.php
<?php
// Autoload
require_once '../vendor/autoload.php';
$app = new SilexApplication();
$app['debug'] = true;
// Init twig
$loader = new Twig_Loader_Filesystem('../views/');
$twig = new Twig_Environment($loader, array('debug' => true));
$twig->addExtension(new Twig_Extension_Debug());
// Need this for my template
$dashboard_url = 'https://XXX.com';
// Register emails which are generated
$emails = new stdClass();
// Proofs
$emails->proof_problem_csr = 'Proof/problem_csr.html.twig';
$emails->proof_problem_mailing = 'Proof/problem_mailing.html.twig';
$emails->proof_new_mailing = 'Proof/new_mailing.html.twig';
$emails->proof_new_csr = 'Proof/new_csr.html.twig';
$emails->proof_problem_client = 'Proof/problem_client.html.twig';
$emails->proof_approved_client = 'Proof/problem_client.html.twig';
$emails->proof_notify_client = 'Proof/approved_client_web.html.twig';
$emails->proof_error_jobnumber_not_found = 'Proof/error_jobnumber_not_found.html.twig';
$emails->proof_notify_shipper_hard_copy = 'Proof/notify_shipper_hard_copy.html.twig';
// File Transfer
$emails->filetransfer_new_csr = 'FileTransfer/new_csr.html.twig';
$emails->filetransfer_new_unknown = 'FileTransfer/new_unknown.html.twig';
// Virtual Prepress
$emails->preflight_ready_csr = 'VirtualPrepress/preflight_ready_csr.html.twig';
// Function for rendering and outputting html files
function outputHtml($twig, $template, $name, $parameters)
{
// Render in Twig
$rendered = $twig->render($template, $parameters);
// Build paths
$output_dir = '../build/';
$finalFilePath = $output_dir.$name.'.html';
// Build return object
$return = new stdClass();
$return->name = $name;
$return->template = $template;
$return->build_path = $finalFilePath;
$return->type = 'updated';
// Check if file exists
if(file_exists($finalFilePath)){
// Get original filesize
$return->size = round(filesize($finalFilePath)/1024);
// Get the existing
$existingContents = file_get_contents($finalFilePath);
// Compare to new
if($existingContents == $rendered){
$return->type = 'no_change';
return $return;
};
} else {
$return->type = 'new';
}
// Write out if something changed
file_put_contents($finalFilePath, $rendered);
// Get updated filesize
$return->size = round(filesize($finalFilePath)/1024);
// Send successful return if a change was made
return $return;
}
$app->get('/', function () use ($emails, $dashboard_url, $twig) {
// Output action
$totalOutputResults = array();
foreach($emails as $name => $template)
{
$parameters = array();
$parameters['dashboard_url'] = $dashboard_url;
$outputResult = outputHtml($twig, $template, $name, $parameters);
array_push($totalOutputResults, $outputResult);
}
// Render in Twig
$rendered = $twig->render('Default/compile.html.twig', array("total_output_results" => $totalOutputResults));
return $rendered;
});
// Run the app
$app->run();
Defaultcompile.html.twig
{% extends 'base.html.twig' %}
{% block body %}
<div class="row">
<div class="col-md-4">
<h3>Emails</h3>
<div class="list-group">
{% for result in total_output_results %}
<a href="../{{ result.build_path }}" target="_blank" class="list-group-item {% spaceless %}
{% if result.type == 'new' %}list-group-item-success{% elseif result.type == 'updated' %}list-group-item-warning{% endif %}
{% endspaceless %}">
{% if result.type == 'new' %}<i class="fa fa-star-o"></i>{% elseif result.type == 'updated' %}<i class="fa fa-pencil-square-o"></i>{% else %}<i class="fa fa-circle-o"></i>{% endif %}
{{ result.name }}
<span class="badge pull-right">{{ result.size }} KB</span>
</a>
{% endfor %}
</div>
</div>
<div class="col-md-4">
<h3>Options</h3>
<a href="{{ app.request.uri }}" class="btn btn-default btn-lg"><i class="fa fa-refresh"></i> Rebuild</a>
</div>
</div>
{% endblock %}
Now the app will generate and in a nice way, display which templates have changed or are new. Each entry in the list is a link which brings you to the compiled html template.
Chat: open-automation @ gitter
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Re: Twig templating with Switch HTML Emails
Rebuilt using Node, Jade, and Gulp. Much simpler now.
https://github.com/dominickp/switch-email-generator
https://github.com/dominickp/switch-email-generator
Chat: open-automation @ gitter
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Re: Twig templating with Switch HTML Emails
Jade converts quote characters to HTML entities which will mess with Switch variables containing quotes. To bypass this, use the != operator to escape raw HTML:gabrielp wrote:Rebuilt using Node, Jade, and Gulp. Much simpler now.
https://github.com/dominickp/switch-email-generator
Code: Select all
p
span(style="font-size:14px;")="VPP Dataset"
br
strong="VPP Action: "
!='[Job.PrivateData:Key="VPP Action"]'
Chat: open-automation @ gitter
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix
Code: open-automation & dominickp @ GitHub
Tools: Switch, Pitstop, EPMS, Veracore, PageDNA, SmartStream, Metrix