Skip to content

Instantly share code, notes, and snippets.

@jellesiderius
Last active March 1, 2023 12:27
Show Gist options
  • Save jellesiderius/bc9c8ea77bfa5a58089e1224e93584a1 to your computer and use it in GitHub Desktop.
Save jellesiderius/bc9c8ea77bfa5a58089e1224e93584a1 to your computer and use it in GitHub Desktop.
Magento 2: Replace old email variable with new ones (Files and Database) 2.4.3 to higher. https://developer.adobe.com/commerce/frontend-core/guide/templates/email-migration/. Place this file in MAGENTO_ROOT/scripts.
<?php
$time_start = microtime(true);
// MAGENTO START
require dirname(__FILE__) . '/../app/bootstrap.php';
use Magento\Framework\App\Bootstrap;
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
/** @var \Psr\Log\LoggerInterface $logger */
$logger = $objectManager->get(\Psr\Log\LoggerInterface::class);
/** @var Magento\Email\Model\ResourceModel\Template\CollectionFactory $templateFactory */
$templateFactory = $objectManager->get(\Magento\Email\Model\ResourceModel\Template\CollectionFactory::class);
$templateFactory = $templateFactory->create();
$templateCollection = $templateFactory->load();
/**
* OPTIONS:
* --dry-run: runs the script without executing this.
* --files: runs the script for files
* --database: runs the script for database files
**/
try {
// CLI Options:
$dryRun = false;
$runForFiles = false;
$runForDatabase = false;
// Set options by CLI variables
if (count($argv) > 0) {
foreach ($argv as $argument) {
if ($argument == '--dry-run') {
$dryRun = true;
}
if ($argument == '--files') {
$runForFiles = true;
}
if ($argument == '--database') {
$runForDatabase = true;
}
}
}
// Key: before value, value: new value
$variableReplaces = [
// General variable:
'htmlescape' => '',
'var=$' => 'var ',
// Variable openers:
'{{ ' => '{{',
' }}' => '}}',
// Store variables:
'store.getFrontendName()' => 'store.frontend_name',
// Order variables:
'order.getCreatedAt()' => 'created_at_formatted',
'order.getCreatedAtFormatted()' => 'created_at_formatted',
'order.getCreatedAtFormatted(1)' => 'created_at_formatted',
'order.getCreatedAtFormatted(2)' => 'created_at_formatted',
'order.getCreatedAtFormatted(3)' => 'created_at_formatted',
'order.getIncrementId()' => 'order.increment_id',
'order.getGrandTotal()' => 'order.grand_total',
'order.getOrderCurrencyCode()' => 'order.order_currency_code',
'order.getBillingAddress().getName()' => 'order_data.customer_name',
'order.getShippingAddress().getName()' => 'order_data.customer_name',
'order.getCustomerName()' => 'order_data.customer_name',
'order.getEmailCustomerNote()' => 'order_data.email_customer_note',
'order.getIsNotVirtual()' => 'order_data.is_not_virtual',
'order.getShippingDescription()' => 'order.shipping_description',
'order.getFrontendStatusLabel()' => 'order_data.frontend_status_label',
'order.getStatusLabel()' => 'order_data.frontend_status_label',
'order.getPayment().getMethodInstance().getTitle()' => 'payment_html|raw',
// Invoice variables:
'invoice.getCreatedAt()' => 'created_at_formatted',
'invoice.getCreatedAtFormatted()' => 'created_at_formatted',
'invoice.getCreatedAtFormatted(1)' => 'created_at_formatted',
'invoice.getCreatedAtFormatted(2)' => 'created_at_formatted',
'invoice.getCreatedAtFormatted(3)' => 'created_at_formatted',
'invoice.getIncrementId()' => 'order.increment_id',
'invoice.getGrandTotal()' => 'order.grand_total',
'invoice.getOrderCurrencyCode()' => 'order.order_currency_code',
'invoice.getBillingAddress().getName()' => 'order_data.customer_name',
'invoice.getShippingAddress().getName()' => 'order_data.customer_name',
'invoice.getCustomerName()' => 'order_data.customer_name',
'invoice.getEmailCustomerNote()' => 'order_data.email_customer_note',
'invoice.getIsNotVirtual()' => 'order_data.is_not_virtual',
'invoice.getShippingDescription()' => 'order.shipping_description',
'invoice.getFrontendStatusLabel()' => 'order_data.frontend_status_label',
'invoice.getStatusLabel()' => 'order_data.frontend_status_label',
'invoice.getPayment().getMethodInstance().getTitle()' => 'payment_html|raw',
'billing.getName()' => 'order_data.customer_name',
'billing.name' => 'order_data.customer_name',
// Handles:
'{{layout handle="sales_email_order_creditmemo_items" creditmemo=$creditmemo order=$order}}' => '{{layout handle="sales_email_order_creditmemo_items" creditmemo_id=$creditmemo_id order_id=$order_id}}',
'{{layout area="frontend" handle="sales_email_order_invoice_items" invoice=$invoice order=$order}}' => '{{layout area="frontend" handle="sales_email_order_invoice_items" invoice_id=$invoice_id order_id=$order_id}}',
'{{layout handle="sales_email_order_invoice_items" invoice=$invoice order=$order}}' => '{{layout area="frontend" handle="sales_email_order_invoice_items" invoice_id=$invoice_id order_id=$order_id}}',
'{{layout handle="sales_email_order_items" order=$order}}' => '{{layout handle="sales_email_order_items" order_id=$order_id area="frontend"}}',
'{{layout handle="sales_email_order_items" order=$order area="frontend"}}' => '{{layout handle="sales_email_order_items" order_id=$order_id area="frontend"}}',
'{{layout handle="sales_email_order_shipment_items" shipment=$shipment order=$order}}' => '{{layout handle="sales_email_order_shipment_items" shipment_id=$shipment_id order_id=$order_id}}',
'{{layout handle="sales_email_order_shipment_track" shipment=$shipment order=$order}}' => '{{layout handle="sales_email_order_shipment_track" shipment_id=$shipment_id order_id=$order_id}}',
'{{block class=\'Magento\\\\Framework\\\\View\\\\Element\\\\Template\' area=\'frontend\' template=\'Magento_Sales::email/shipment/track.phtml\' shipment=$shipment order=$order}}' => '{{layout
handle="sales_email_order_shipment_track" shipment_id=$shipment_id order_id=$order_id}}',
// Amasty Gift Code emails
'gcard_email.getGiftCode()' => 'gcard_email.gift_code',
'gcard_email.getExpiryDays()' => 'gcard_email.expiry_days',
'gcard_email.getRecipientName()' => 'gcard_email.recipient_name',
'gcard_email.getSenderName()' => 'gcard_email.sender_name',
'gcard_email.getSenderEmail()' => 'gcard_email.sender_email',
'gcard_email.getSenderMessage()' => 'gcard_email.sender_message',
'gcard_email.getBalance()' => 'gcard_email.balance',
'gcard_email.getExpiredDate()' => 'gcard_email.expired_date',
'gcard_email.getImage()' => 'gcard_email.image',
// Magetrend variables
"mtVar.getData('invoice_increment_id')" => "invoice.increment_id",
"mtVar.getData('invoice_increment_id')" => "invoice.increment_id",
"mtVar.getData( 'formatted_grand_total')" => 'mtVar.getFormattedGrandTotal()',
"mtVar.getData('formatted_grand_total')" => 'mtVar.getFormattedGrandTotal()'
];
$replacedArray = [];
$replaceFileItems = 0;
$replaceDbItems = 0;
// Gather all emails for code + theme
$frontendDir = BP . '/app/design/frontend';
$appCodeDir = BP . '/app/code';
$frontendHtmlFiles = getDirHtmlFiles($frontendDir);
$appCodeDirFiles = getDirHtmlFiles($appCodeDir);
$mergedHtmlFilePaths = array_merge($frontendHtmlFiles, $appCodeDirFiles);
if ($runForFiles) {
// Find and replace in emails (files)
foreach ($mergedHtmlFilePaths as $k => $htmlFilePath) {
$fileContents = file_get_contents($htmlFilePath);
// Check if file is an email
if (strstr($fileContents, '@subject') === false) {
continue;
}
$mutatedFile = false;
$hasCountedFileItem = false;
// Find and replace in email content
foreach ($variableReplaces as $oldValue => $newValue) {
if (strstr($fileContents, $oldValue) !== false) {
if (!$hasCountedFileItem) {
$replaceFileItems++;
$hasCountedFileItem = true;
}
if ($dryRun) {
$replacedArray[$htmlFilePath][] = 'DRY RUN: Would replace file content: "' . $oldValue . '" -> "' . $newValue . '"';
} else {
$replacedArray[$htmlFilePath][] = 'Replaced file content: "' . $oldValue . '" -> "' . $newValue . '"';
$fileContents = str_replace($oldValue, $newValue, $fileContents);
$mutatedFile = true;
}
}
}
// Overwrite file with new content
if (!$dryRun && $mutatedFile) {
file_put_contents($htmlFilePath, $fileContents);
}
}
}
if ($runForDatabase) {
if (class_exists('Magetrend\Email\Model\Variable')) {
/** @var Magetrend\Email\Model\Variable $mtModel */
$mtModel = $objectManager->get(\Magetrend\Email\Model\Variable::class);
$mtEmailCollection = $mtModel->getCollection();
foreach ($mtEmailCollection as $mtEmailItem) {
$mtEmailItemVarValue = $mtEmailItem->getVarValue();
$mutatedMtItem = false;
$dbTemplateId = "MT ITEM ID: " . $mtEmailItem->getEntityId();
foreach ($variableReplaces as $oldValue => $newValue) {
if (strstr($mtEmailItemVarValue, $oldValue) !== false) {
$mtEmailItemVarValue = str_replace($oldValue, $newValue, $mtEmailItemVarValue);
$mtEmailItem->setVarValue($mtEmailItemVarValue);
$mtEmailItem->save();
$replacedArray[$dbTemplateId][] = 'Replaced text: "' . $oldValue . '" -> "' . $newValue . '"';
}
}
}
}
foreach ($templateCollection as $template) {
/** @var \Magento\Email\Model\Template $template */
$templateTitle = $template->getTemplateSubject();
$templateText = $template->getTemplateText();
$mutatedDbItem = false;
$hasCountedDbItem = false;
$dbTemplateId = "Database ID: " . $template->getId() . " (" . $template->getTemplateCode() . ")";
// Find and replace in title
foreach ($variableReplaces as $oldValue => $newValue) {
if (strstr($templateTitle, $oldValue) !== false) {
if (!$hasCountedDbItem) {
$replaceDbItems++;
$hasCountedDbItem = true;
}
if ($dryRun) {
$replacedArray[$dbTemplateId][] = 'DRY RUN: Would replace title: "' . $oldValue . '" -> "' . $newValue . '"';
} else {
$replacedArray[$dbTemplateId][] = 'Replaced title/subject: "' . $oldValue . '" -> "' . $newValue . '"';
$templateTitle = str_replace($oldValue, $newValue, $templateTitle);
$mutatedDbItem = true;
$template->setTemplateSubject($templateTitle);
}
}
}
// Find and replace in content
foreach ($variableReplaces as $oldValue => $newValue) {
if (strstr($templateText, $oldValue) !== false) {
if (!$hasCountedDbItem) {
$replaceDbItems++;
$hasCountedDbItem = true;
}
if ($dryRun) {
$replacedArray[$dbTemplateId][] = 'DRY RUN: Would replace text: "' . $oldValue . '" -> "' . $newValue . '"';
} else {
$replacedArray[$dbTemplateId][] = 'Replaced text: "' . $oldValue . '" -> "' . $newValue . '"';
$templateText = str_replace($oldValue, $newValue, $templateText);
$mutatedDbItem = true;
$template->setTemplateText($templateText);
}
}
}
if ($mutatedDbItem) {
$template->save();
}
}
}
if ($runForDatabase) {
}
$replacedFileCount = $replaceFileItems + $replaceDbItems;
if ($replacedFileCount > 0) {
print_r($replacedArray);
echo "\n";
echo "==================================================================";
echo "\n";
if ($dryRun) {
echo "DRY RUN: $replacedFileCount items would have been edited. Files: $replaceFileItems, DB items: $replaceDbItems\n";
} else {
echo "$replacedFileCount items have been edited. Files: $replaceFileItems, DB items: $replaceDbItems \n";
}
} else {
echo "Nothing has been replaced. Note: you can use '--files' and/or '--database' as variables to the file as a command.\n";
}
} catch (Exception $exception) {
$logger->critical($exception);
}
$time_end = microtime(true);
//dividing with 60 will give the execution time in minutes other wise seconds
$execution_time = ($time_end - $time_start) / 60;
//execution time of the script
echo 'Total Execution Time: ' . $execution_time . ' Mins';
echo "\n";
echo "==================================================================";
function getDirHtmlFiles($dir, &$results = [])
{
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path)) {
if (strstr($path, '.html') !== false) {
$results[] = $path;
}
} elseif ($value != "." && $value != "..") {
getDirHtmlFiles($path, $results);
}
}
return $results;
}
@LauHypershop
Copy link

Might be better to move
'htmlescape' => '',
above
'{{ ' => '{{',
since it's likely to cause some whitespace just after the curly braces.

@LauHypershop
Copy link

Invoices don't seem to support the created_at_formatted variable, so that should probably be:

        'invoice.getCreatedAt()' => 'invoice.created_at|raw',
        'invoice.getCreatedAtFormatted()' => 'created_at|raw',
        'invoice.getCreatedAtFormatted(1)' => 'created_at|raw',
        'invoice.getCreatedAtFormatted(2)' => 'created_at|raw',
        'invoice.getCreatedAtFormatted(3)' => 'created_at|raw',

If we want formatting maybe we should make a filter for that. Currently it gives you date & time, we could make a filter to strip the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment