2

I'm trying to build a system where a client can use shortcodes inside square tags when building an email template (also stored in the database) which will then be replaced with a line of PHP code. For example [order_date] would be replaced with the value of date("l jS F Y", strtotime($OrderDate)), with OrderDate having been defined further up the code.

To do this I built a new database table with two fields - SubOriginal and SubReplacement. In the example above, [order_date] would be in the SubOriginal field, and date("l jS F Y", strtotime($OrderDate)) would be in the SubReplacement field.

Then when it comes to emailing the user, I have this code:

 // Set fields (StackOverflow example - data from a previous db query)
 $OrderDate = $row['OrderDate'];

 // Get customer order confirmation template
 $sql = "SELECT DeliveryTemplateSubject, DeliveryTemplateContent FROM delivery_templates WHERE DeliveryTemplateTemplate='1'";
 $set = $link->query($sql);
 $row = $set->fetch_row();
 $MessageBody = nl2br($row[1]);

 // Make template substitutions
 $sqlsub = "SELECT * FROM templates_subs";
 $setsub = $link->query($sqlsub);
 while($rowsub = $setsub->fetch_array(MYSQLI_ASSOC))
 {
  $replacement = $rowsub['SubReplacement'];
  $MessageBody = str_replace($rowsub['SubOriginal'], $replacement, $MessageBody);
 }

 // Email customer
 $subject = $row[0];
 mail($CustomerEmail, $subject, $MessageBody);

However the replacements all come out as the original PHP code starting with the dollar sign.

Where am I going wrong?

Stuart Pinfold
  • 318
  • 1
  • 5
  • 19
  • Well if you store `date("l jS F Y", strtotime($OrderDate))` exactly like that in the DB you'd need to start using [eval](http://php.net/manual/en/function.eval.php) which really should be avoided for security. I'd suggest databasing the name of a callback function that exists to run instead. eg `[order_date]` could run a function `shortcode_order_date()` instead via http://php.net/manual/en/function.call-user-func.php as one solution. You may even need to look into http://php.net/manual/en/function.preg-replace-callback.php – Scuzzy Jan 05 '18 at 12:25
  • 2
    "However the replacements all come out as the original PHP code starting with the dollar sign." - Please post an example. – Paul Spiegel Jan 05 '18 at 12:49
  • @Paul Spiegel Using my example in the original post, if the template reads "You ordered on [order_date]", the email comes out as "You ordered on $OrderDate" whereas I'd like it to say "You ordered on Friday 5th January 2018". – Stuart Pinfold Jan 05 '18 at 13:33
  • @Scuzzy having a PHP function called (your example) "shortcode_order_date" negates the point of doing this via a database in the first place, which is so that my client can add new shortcodes (and associated PHP) without having to edit the PHP code. However you have given me an idea which is to use one function and pass the name of the shortcode to it, I guess I'd also need to put every shortcode into an array first to the function can reference it. Still, how could I turn the string into an executed bit of PHP code without using Eval? – Stuart Pinfold Jan 05 '18 at 13:37
  • 1
    Eval would be the only way short of attempting to decode the string into components to try to call – Scuzzy Jan 05 '18 at 13:49
  • IMO, storing email templates in the database is less than ideal, you can take a look at [this](https://stackoverflow.com/questions/3706855/send-email-with-a-template-using-php) question on how to make email templates, maybe it can give you different ideas for different approaches to this problem – William Perron Jan 05 '18 at 14:06
  • How does Wordpress do this exact thing? Read their shortcode code and replicate, no point reinventing the wheel. – ggdx Jan 05 '18 at 14:24
  • Why don't you just write one line per placeholder (like `$MessageBody = str_replace('[order_date]', date("l jS F Y", strtotime($OrderDate)), $MessageBody);`) and forget the `templates_subs` table entirely? – Paul Spiegel Jan 05 '18 at 17:24
  • @Paul Spiegel because then to add or edit shortcode tags the original PHP file would need to be edited. The whole point of doing this in a database is to provide my client a way to manage shortcode tags from a custom admin area. – Stuart Pinfold Jan 06 '18 at 18:18
  • But you already have this line: `$OrderDate = $row['OrderDate'];`. And you will need to do that for every placeholder. And you still need to put the transformation code (`strtotime(...)`) somewehere. – Paul Spiegel Jan 06 '18 at 18:57
  • @PaulSpiegel will I need to do that for every shortcode? Does eval not have access to variables further up the same code? I've managed to remove all eval() errors (by escaping apostrophes and removing apostrophes from array references) but the email is now coming through with no information at all filling the placeholders. Is this why? I assumed previously-defined variables would be available inside the eval() function? – Stuart Pinfold Jan 08 '18 at 10:14

0 Answers0