This Opencart tutorial shows how to change and customize email send out to the store administrator when they get the new order in the OpenCart store. Normally Opencart just sends an email with fewer details like below:

You have received an order.

Order ID: 1088
Date Added: 11/02/2019
Order Status: Complete

Products
1x .... $0.00

Order Totals
Sub-Total: $0.00
Total: $0.00

Let’s change that email to send full details like the one that customers get.

Open catalog/controller/mail/order.php and remove the alert method and replace with below alert method.

// Admin Alert Mail
public function alert(&$route, &$args) {
    if (isset($args[0])) {
        $order_id = $args[0];
    } else {
        $order_id = 0;
    }
    
    if (isset($args[1])) {
        $order_status_id = $args[1];
    } else {
        $order_status_id = 0;
    }	
    
    if (isset($args[2])) {
        $comment = $args[2];
    } else {
        $comment = '';
    }
    
    if (isset($args[3])) {
        $notify = $args[3];
    } else {
        $notify = '';
    }

    $order_info = $this->model_checkout_order->getOrder($order_id);
    
    if ($order_info && !$order_info['order_status_id'] && $order_status_id && in_array('order', (array)$this->config->get('config_mail_alert'))) {	

        // Check for any downloadable products
    $download_status = false;

    $order_products = $this->model_checkout_order->getOrderProducts($order_info['order_id']);
    
    foreach ($order_products as $order_product) {
        // Check if there are any linked downloads
        $product_download_query = $this->db->query("SELECT COUNT(*) AS total FROM `" . DB_PREFIX . "product_to_download` WHERE product_id = '" . (int)$order_product['product_id'] . "'");

        if ($product_download_query->row['total']) {
            $download_status = true;
        }
    }
    
    // Load the language for any mails that might be required to be sent out
    $language = new Language($order_info['language_code']);
    $language->load($order_info['language_code']);
    $language->load('mail/order_add');
$this->load->language('mail/order_alert');

    // HTML Mail
    $data['title'] = sprintf($language->get('text_subject'), $order_info['store_name'], $order_info['order_id']);

    $data['text_greeting'] = sprintf($language->get('text_greeting'), $order_info['store_name']);
    $data['text_link'] = $language->get('text_link');
    $data['text_download'] = $language->get('text_download');
    $data['text_order_detail'] = $language->get('text_order_detail');
    $data['text_instruction'] = $language->get('text_instruction');
    $data['text_order_id'] = $language->get('text_order_id');
    $data['text_date_added'] = $language->get('text_date_added');
    $data['text_payment_method'] = $language->get('text_payment_method');
    $data['text_shipping_method'] = $language->get('text_shipping_method');
    $data['text_email'] = $language->get('text_email');
    $data['text_telephone'] = $language->get('text_telephone');
    $data['text_ip'] = $language->get('text_ip');
    $data['text_order_status'] = $language->get('text_order_status');
    $data['text_payment_address'] = $language->get('text_payment_address');
    $data['text_shipping_address'] = $language->get('text_shipping_address');
    $data['text_product'] = $language->get('text_product');
    $data['text_model'] = $language->get('text_model');
    $data['text_quantity'] = $language->get('text_quantity');
    $data['text_price'] = $language->get('text_price');
    $data['text_total'] = $language->get('text_total');
    $data['text_footer'] = $language->get('text_footer');

    $data['logo'] = $order_info['store_url'] . 'image/' . $this->config->get('config_logo');
    $data['store_name'] = $order_info['store_name'];
    $data['store_url'] = $order_info['store_url'];
    $data['customer_id'] = $order_info['customer_id'];
    $data['link'] = $order_info['store_url'] . 'index.php?route=account/order/info&order_id=' . $order_info['order_id'];

    if ($download_status) {
        $data['download'] = $order_info['store_url'] . 'index.php?route=account/download';
    } else {
        $data['download'] = '';
    }

    $data['order_id'] = $order_info['order_id'];
    $data['date_added'] = date($language->get('date_format_short'), strtotime($order_info['date_added']));
    $data['payment_method'] = $order_info['payment_method'];
    $data['shipping_method'] = $order_info['shipping_method'];
    $data['email'] = $order_info['email'];
    $data['telephone'] = $order_info['telephone'];
    $data['ip'] = $order_info['ip'];

    $order_status_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_status WHERE order_status_id = '" . (int)$order_status_id . "' AND language_id = '" . (int)$order_info['language_id'] . "'");

    if ($order_status_query->num_rows) {
        $data['order_status'] = $order_status_query->row['name'];
    } else {
        $data['order_status'] = '';
    }

    if ($comment && $notify) {
        $data['comment'] = nl2br($comment);
    } else {
        $data['comment'] = '';
    }

    if ($order_info['payment_address_format']) {
        $format = $order_info['payment_address_format'];
    } else {
        $format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
    }

    $find = array(
        '{firstname}',
        '{lastname}',
        '{company}',
        '{address_1}',
        '{address_2}',
        '{city}',
        '{postcode}',
        '{zone}',
        '{zone_code}',
        '{country}'
    );

    $replace = array(
        'firstname' => $order_info['payment_firstname'],
        'lastname'  => $order_info['payment_lastname'],
        'company'   => $order_info['payment_company'],
        'address_1' => $order_info['payment_address_1'],
        'address_2' => $order_info['payment_address_2'],
        'city'      => $order_info['payment_city'],
        'postcode'  => $order_info['payment_postcode'],
        'zone'      => $order_info['payment_zone'],
        'zone_code' => $order_info['payment_zone_code'],
        'country'   => $order_info['payment_country']
    );

    $data['payment_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));

    if ($order_info['shipping_address_format']) {
        $format = $order_info['shipping_address_format'];
    } else {
        $format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
    }

    $find = array(
        '{firstname}',
        '{lastname}',
        '{company}',
        '{address_1}',
        '{address_2}',
        '{city}',
        '{postcode}',
        '{zone}',
        '{zone_code}',
        '{country}'
    );

    $replace = array(
        'firstname' => $order_info['shipping_firstname'],
        'lastname'  => $order_info['shipping_lastname'],
        'company'   => $order_info['shipping_company'],
        'address_1' => $order_info['shipping_address_1'],
        'address_2' => $order_info['shipping_address_2'],
        'city'      => $order_info['shipping_city'],
        'postcode'  => $order_info['shipping_postcode'],
        'zone'      => $order_info['shipping_zone'],
        'zone_code' => $order_info['shipping_zone_code'],
        'country'   => $order_info['shipping_country']
    );

    $data['shipping_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));

    $this->load->model('tool/upload');

    // Products
    $data['products'] = array();

    foreach ($order_products as $order_product) {
        $option_data = array();

        $order_options = $this->model_checkout_order->getOrderOptions($order_info['order_id'], $order_product['order_product_id']);

        foreach ($order_options as $order_option) {
            if ($order_option['type'] != 'file') {
                $value = $order_option['value'];
            } else {
                $upload_info = $this->model_tool_upload->getUploadByCode($order_option['value']);

                if ($upload_info) {
                    $value = $upload_info['name'];
                } else {
                    $value = '';
                }
            }

            $option_data[] = array(
                'name'  => $order_option['name'],
                'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
            );
        }

        $data['products'][] = array(
            'name'     => $order_product['name'],
            'model'    => $order_product['model'],
            'option'   => $option_data,
            'quantity' => $order_product['quantity'],
            'price'    => $this->currency->format($order_product['price'] + ($this->config->get('config_tax') ? $order_product['tax'] : 0), $order_info['currency_code'], $order_info['currency_value']),
            'total'    => $this->currency->format($order_product['total'] + ($this->config->get('config_tax') ? ($order_product['tax'] * $order_product['quantity']) : 0), $order_info['currency_code'], $order_info['currency_value'])
        );
    }

    // Vouchers
    $data['vouchers'] = array();

    $order_vouchers = $this->model_checkout_order->getOrderVouchers($order_info['order_id']);

    foreach ($order_vouchers as $order_voucher) {
        $data['vouchers'][] = array(
            'description' => $order_voucher['description'],
            'amount'      => $this->currency->format($order_voucher['amount'], $order_info['currency_code'], $order_info['currency_value']),
        );
    }

    // Order Totals
    $data['totals'] = array();
    
    $order_totals = $this->model_checkout_order->getOrderTotals($order_info['order_id']);

    foreach ($order_totals as $order_total) {
        $data['totals'][] = array(
            'title' => $order_total['title'],
            'text'  => $this->currency->format($order_total['value'], $order_info['currency_code'], $order_info['currency_value']),
        );
    }

    $this->load->model('setting/setting');
    
    $from = $this->model_setting_setting->getSettingValue('config_email', $order_info['store_id']);
    
    if (!$from) {
        $from = $this->config->get('config_email');
    }


        $mail = new Mail($this->config->get('config_mail_engine'));
        $mail->parameter = $this->config->get('config_mail_parameter');
        $mail->smtp_hostname = $this->config->get('config_mail_smtp_hostname');
        $mail->smtp_username = $this->config->get('config_mail_smtp_username');
        $mail->smtp_password = html_entity_decode($this->config->get('config_mail_smtp_password'), ENT_QUOTES, 'UTF-8');
        $mail->smtp_port = $this->config->get('config_mail_smtp_port');
        $mail->smtp_timeout = $this->config->get('config_mail_smtp_timeout');

        $mail->setTo($this->config->get('config_email'));
        $mail->setFrom($this->config->get('config_email'));
        $mail->setSender(html_entity_decode($order_info['store_name'], ENT_QUOTES, 'UTF-8'));
        $mail->setSubject(html_entity_decode(sprintf($this->language->get('text_subject'), $this->config->get('config_name'), $order_info['order_id']), ENT_QUOTES, 'UTF-8'));
        $mail->setHtml($this->load->view('mail/order_alert', $data));
        $mail->send();

        // Send to additional alert emails
        $emails = explode(',', $this->config->get('config_mail_alert_email'));

        foreach ($emails as $email) {
            if ($email && filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $mail->setTo($email);
                $mail->send();
            }
        }
    }
}

Then go to catalog/view/theme/YOUR_THEME/template/mail/order_mail.twig and remove all the code and replace with the following codes:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{ title }}</title>
</head>
<body style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; color: #000000;">
<div style="width: 680px;"><a href="{{ store_url }}" title="{{ store_name }}"><img src="{{ logo }}" alt="{{ store_name }}" style="margin-bottom: 20px; border: none;" /></a>
  <p style="margin-top: 0px; margin-bottom: 20px;">{{ text_greeting }}</p>
  
  {% if download %}
  <p style="margin-top: 0px; margin-bottom: 20px;">{{ text_download }}</p>
  <p style="margin-top: 0px; margin-bottom: 20px;"><a href="{{ download }}">{{ download }}</a></p>
  <{% endif %}
  <table style="border-collapse: collapse; width: 100%; border-top: 1px solid #DDDDDD; border-left: 1px solid #DDDDDD; margin-bottom: 20px;">
    <thead>
      <tr>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;" colspan="2">{{ text_order_detail }}</td>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;"><b>{{ text_order_id }}</b> {{ order_id }}<br />
          <b>{{ text_date_added }}</b> {{ date_added }}<br />
          <b>{{ text_payment_method }}</b> {{ payment_method }}<br />
          {% if shipping_method %} <b>{{ text_shipping_method }}</b> {{ shipping_method }}
          {% endif %}</td>
        <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;"><b>{{ text_email }}</b> {{ email }}<br />
          <b>{{ text_telephone }}</b> {{ telephone }}<br />
          <b>{{ text_ip }}</b> {{ ip }}<br />
          <b>{{ text_order_status }}</b> {{ order_status }}<br /></td>
      </tr>
    </tbody>
  </table>
  {% if comment %}
  <table style="border-collapse: collapse; width: 100%; border-top: 1px solid #DDDDDD; border-left: 1px solid #DDDDDD; margin-bottom: 20px;">
    <thead>
      <tr>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;">{{ text_instruction }}</td>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ comment }}</td>
      </tr>
    </tbody>
  </table>
  {% endif %}
  <table style="border-collapse: collapse; width: 100%; border-top: 1px solid #DDDDDD; border-left: 1px solid #DDDDDD; margin-bottom: 20px;">
    <thead>
      <tr>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;">{{ text_payment_address }}</td>
        {% if shipping_address %}
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;">{{ text_shipping_address }}</td>
        {% endif %} </tr>
    </thead>
    <tbody>
      <tr>
        <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ payment_address }}</td>
        {% if shipping_address %}
        <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ shipping_address }}</td>
        {% endif %} </tr>
    </tbody>
  </table>
  <table style="border-collapse: collapse; width: 100%; border-top: 1px solid #DDDDDD; border-left: 1px solid #DDDDDD; margin-bottom: 20px;">
    <thead>
      <tr>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;">{{ text_product }}</td>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: left; padding: 7px; color: #222222;">{{ text_model }}</td>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: right; padding: 7px; color: #222222;">{{ text_quantity }}</td>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: right; padding: 7px; color: #222222;">{{ text_price }}</td>
        <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; background-color: #EFEFEF; font-weight: bold; text-align: right; padding: 7px; color: #222222;">{{ text_total }}</td>
      </tr>
    </thead>
    <tbody>
    
    {% for product in products %}
    <tr>
      <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ product.name }}
        {% for option in product.option %}<br />
         <small> - {{ option.name }}: {{ option.value }}</small>{% endfor %}</td>
      <td style="font-size: 12px; border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ product.model }}</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ product.quantity }}</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ product.price }}</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ product.total }}</td>
    </tr>
    {% endfor %}
    {% for voucher in vouchers %}
    <tr>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;">{{ voucher.description }}</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: left; padding: 7px;"></td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">1</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ voucher.amount }}</td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ voucher.amount }}</td>
    </tr>
    {% endfor %}
      </tbody>
    
    <tfoot>
    
    {% for total in totals %}
    <tr>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;" colspan="4"><b>{{ total.title }}:</b></td>
      <td style="font-size: 12px;	border-right: 1px solid #DDDDDD; border-bottom: 1px solid #DDDDDD; text-align: right; padding: 7px;">{{ total.text }}</td>
    </tr>
    {% endfor %}
      </tfoot>
    
  </table>
  <p style="margin-top: 0px; margin-bottom: 20px;">{{ text_footer }}</p>
</div>
</body>
</html>

With these changes you can get the customized full detail email for Admin as well.

If you want to change the email design for the affiliate alert, affiliate welcome email, forgotten password email, order notification to customer, order alert to store administrator, edit order alert, register alert, register notification to customer, transaction alert, voucher alert, you can change them at catalog/view/theme/YOUR_TEME/template/mail where you can change your design as per your need.

Let us know if you find any difficulties or need any help from us. Enjoy!.

3 COMMENTS

  1. Thank you, I have been looking for this solution for months and you have helped me a lot of funcinou perfectly, serial legal after creating an extension I believe will facilitate many people’s lives thank you.

  2. Hi.
    I am trying to apply this modification but my Opecart does not have the file below:
    catalog / view / theme / YOUR_THEME / template / mail / order_mail.twig

    In thema it does not exist, and in default / basic there are only these other files:

    order_add.twig
    order_alert.twig
    order_edit.twig

    What appears to contain the same as the order.twig file is the order_add.twig. I can change this, or I must create an order.twig in the mail directory of the template (which does not currently exist).

    Thank you for your help.

LEAVE A REPLY

Please enter your comment!
Please enter your name here