Skip to Content

New J2Commerce 6.6.5 is out. Here is everything in the release.

See What’s New
Account
Enter the email address on your account.
Forgot your username?
Enter your password.
Forgot your password?

Or continue with

Open Public Category: Feature Requests Ticket #1065

[STATUS_COMMENT] - a new tag for the message template

This is a public ticket

Everybody will be able to see its contents. Do not include usernames, passwords or any other sensitive information.

J2Commerce

Version
J2Commerce v6

Conversation

Krzysztof Kuznowicz

I noticed that seller-written status comments are not delivered to customers in email notifications sent through bulk actions. This functionality may not have been implemented, but I consider it a clear bug. I am attaching a ready-to-use patch that resolves the issue. The status comment can be included in an email template as follows:

[IF:STATUS_COMMENT]
Message regarding your order status:
[STATUS_COMMENT]
[/IF:STATUS_COMMENT]

I know you don't like it when people post ready-made solutions, but I don't like having to fix my store after the official, incomplete component updates ;-)
Below is a patch you can paste directly into Git

best,
KK

 

---------------------------------------

diff --git a/administrator/components/com_j2commerce/src/Controller/OrderController.php b/administrator/components/com_j2commerce/src/Controller/OrderController.php
--- a/administrator/components/com_j2commerce/src/Controller/OrderController.php
+++ b/administrator/components/com_j2commerce/src/Controller/OrderController.php
@@ -210,7 +210,7 @@ class OrderController extends FormController
if ($notify) {
$order = $model->getItem($orderId);
$notifyResult = $order && !empty($order->order_id)
- ? $model->sendOrderNotification($order->order_id, true, true)
+ ? $model->sendOrderNotification($order->order_id, true, true, $comment)
: ['customer_sent' => 0, 'errors' => []];

if (($notifyResult['customer_sent'] ?? 0) === 0) {
diff --git a/administrator/components/com_j2commerce/src/Controller/OrdersController.php b/administrator/components/com_j2commerce/src/Controller/OrdersController.php
--- a/administrator/components/com_j2commerce/src/Controller/OrdersController.php
+++ b/administrator/components/com_j2commerce/src/Controller/OrdersController.php
@@ -123,7 +123,7 @@ class OrdersController extends AdminController
continue;
}

- $notifyResult = $model->sendOrderNotification($order->order_id, true, true);
+ $notifyResult = $model->sendOrderNotification($order->order_id, true, true, $comment);

if (($notifyResult['customer_sent'] ?? 0) === 0) {
$missingTemplateIds[] = $order->order_id;
diff --git a/administrator/components/com_j2commerce/src/Model/OrderModel.php b/administrator/components/com_j2commerce/src/Model/OrderModel.php
--- a/administrator/components/com_j2commerce/src/Model/OrderModel.php
+++ b/administrator/components/com_j2commerce/src/Model/OrderModel.php
@@ -1221,7 +1221,7 @@ class OrderModel extends AdminModel

// Send notification emails when requested
if ($notify) {
- $this->sendOrderNotification($order->order_id, true, true);
+ $this->sendOrderNotification($order->order_id, true, true, $comment);
}

return true;
@@ -4348,10 +4348,16 @@ class OrderModel extends AdminModel
* @param string $orderId The order_id (varchar).
* @param bool $notifyCustomer Send to customer.
* @param bool $notifyAdmin Send to admin.
+ * @param string $statusComment Comment entered for this status change.
*
* @return array{sent: int, customer_sent: int, admin_sent: int, errors: string[]}
*/
- public function sendOrderNotification(string $orderId, bool $notifyCustomer = true, bool $notifyAdmin = true): array
+ public function sendOrderNotification(
+ string $orderId,
+ bool $notifyCustomer = true,
+ bool $notifyAdmin = true,
+ string $statusComment = ''
+ ): array
{
$result = ['sent' => 0, 'customer_sent' => 0, 'admin_sent' => 0, 'errors' => []];

@@ -4376,6 +4382,10 @@ class OrderModel extends AdminModel
return $result;
}

+ // Transient context for the email generated by this status-change operation.
+ // Do not recover it from order history: history also contains system and mail-log rows.
+ $order->status_comment = $statusComment;
+
$emailHelper = EmailHelper::getInstance();

PluginHelper::importPlugin('j2commerce');
diff --git a/administrator/components/com_j2commerce/src/Helper/EmailHelper.php b/administrator/components/com_j2commerce/src/Helper/EmailHelper.php
--- a/administrator/components/com_j2commerce/src/Helper/EmailHelper.php
+++ b/administrator/components/com_j2commerce/src/Helper/EmailHelper.php
@@ -89,6 +89,7 @@ class EmailHelper
'[DOWNLOAD_LINKS]',
// Escaped at assignment, before nl2br() adds the only markup it carries.
'[CUSTOMER_NOTE]',
+ '[STATUS_COMMENT]',
'[BANK_TRANSFER_INFORMATION]',
'[PAYMENT_INSTRUCTIONS]',
'[FOOTER_TEXT]',
@@ -945,6 +946,7 @@ class EmailHelper
'[SHIPPING_TYPE]' => $language->_($shipping->ordershipping_name ?? ''),
'[SHIPPING_TRACKING_ID]' => $shipping->ordershipping_tracking_id ?? '',
'[CUSTOMER_NOTE]' => self::encodeTagDelimiters(nl2br(htmlspecialchars((string) ($order->customer_note ?? ''), ENT_QUOTES, 'UTF-8'))),
+ '[STATUS_COMMENT]' => self::encodeTagDelimiters(nl2br(htmlspecialchars((string) ($order->status_comment ?? ''), ENT_QUOTES, 'UTF-8'))),
'[PAYMENT_TYPE]' => $this->getPaymentMethodTitle($order->orderpayment_type ?? '', $language),
'[ORDER_TOKEN]' => $isAdminCopy ? '' : $orderToken,
'[TOKEN]' => $isAdminCopy ? '' : $orderToken,
diff --git a/administrator/components/com_j2commerce/src/Helper/MessageHelper.php b/administrator/components/com_j2commerce/src/Helper/MessageHelper.php
--- a/administrator/components/com_j2commerce/src/Helper/MessageHelper.php
+++ b/administrator/components/com_j2commerce/src/Helper/MessageHelper.php
@@ -101,6 +101,7 @@ class MessageHelper
* - [SITEURL]: Website URL
* - [INVOICE_URL]: Link to customer invoice/order page
* - [CUSTOMER_NOTE]: Customer notes from checkout
+ * - [STATUS_COMMENT]: Comment entered for the current order status change
* - [PAYMENT_TYPE]: Payment method used
* - [SHIPPING_TYPE]: Shipping method used
* - [ORDERID]: Order ID number
@@ -133,6 +134,7 @@ class MessageHelper
'[GUEST_ORDER_URL]' => Text::_('COM_J2COMMERCE_EMAILTEMPLATE_TAG_GUEST_ORDER_URL'),
'[DOWNLOAD_LINKS]' => Text::_('COM_J2COMMERCE_EMAILTEMPLATE_TAG_DOWNLOAD_LINKS'),
'[CUSTOMER_NOTE]' => Text::_('COM_J2COMMERCE_EMAILTEMPLATE_TAG_CUSTOMER_NOTE'),
+ '[STATUS_COMMENT]' => Text::_('COM_J2COMMERCE_FIELD_STATUS_COMMENT'),
'[PAYMENT_TYPE]' => Text::_('COM_J2COMMERCE_EMAILTEMPLATE_TAG_PAYMENT_TYPE'),
'[SHIPPING_TYPE]' => Text::_('COM_J2COMMERCE_SHIPM_SHIPPING_TYPE'),
'[ORDERID]' => Text::_('COM_J2COMMERCE_EMAILTEMPLATE_TAG_ORDERID'),

Adam Melcher Staff

K,

 

Let me work on this. In the meantime, I am not sure if you are aware, but the visual builder email templates are multilingual and allow you to manage all of your languages in one place and they automatically send the language locale that matches the order's language locale:
email language 2

email language 3

email language 4

email language 5

Krzysztof Kuznowicz

Hi Adam,


I didn't know that, and I'll take a look at it when I have some free time—so I understand I don't need to have separate language versions anymore?
Thanks for the info, :)


Best regards
KK

Adam Melcher Staff

Krzysztof,

That is correct. One email template for as many languages you offer translated in the backed language of the store administrator's preferred language and each block of content (whether's a title, label, subject line, etc can manage every translation you offer from the modal popups that save any changes directly into your language overrides folder without leaving the email's edit screen. It also allows you to use if blocks so you can show x if y is true - and they have event hooks so you can have additional content automatically inserted into email templates such as our upcoming points and rewards app that can display the shopper's current points total that is calculated at the time the email is sent out without the store owner needed to do anything on their end.

It should make life easier for you once you get used to it... :)

 

Adam

Krzysztof Kuznowicz

such as our upcoming points and rewards app that can display the shopper's current points total that is calculated at the time the email is sent out without the store owner needed to do anything on their end.

Actually, I built the foundations of this system years ago when I was still using VirtueMart. I tried to share some of these ideas with their developers, but unfortunately they seemed more interested in judging me personally than discussing mechanisms that could genuinely improve the store. That was also one of the reasons I eventually came here.

What I like about your team is that you seem to think ahead and focus on where the product can go in the future, rather than defending your own ego.
About a month ago I rebuilt my ideas for J2Commerce as three independent components. The first is Price Manager. It handles automatic pricing rules based on time, permissions, SKU, categories and Joomla tags.


I also added my own loyalty system that doesn't require customer accounts. It calculates permanent discount levels from the number and value of previous orders within a defined period, for example the last three years. Older orders automatically stop counting, and customers who return goods can lose their loyalty discount. So it's based on actual purchasing history rather than points or user groups.

Attachments

Loyal-customer-discount.png
Loyal-customer-discounts-rule.png
campaign.png
prices.png
Krzysztof Kuznowicz

The second component I built is an orphaned image manager for Joomla Content, J2Commerce and Falang. This was actually one of the first things I made after migrating to J2Commerce, because I couldn't find any official solution for managing this in stores with thousands of products. It scans selected Joomla categories and detects images that are no longer referenced by any content or product. Instead of deleting them immediately, it moves them into quarantine first, so they can be verified before final deletion.
I also made it Falang-aware. It checks image dependencies between language versions and can detect situations where a translated article is missing its own images or is still using the images from the original language version. Obviously this isn't something every small store needs, but with thousands of products constantly being added, changed and removed, orphaned images accumulate very quickly. After a few years they can leave a considerable amount of completely unused data on the server.