OpenCart 3.0+ 运费模块新增多选功能需求
Got it, let's walk through how to add multiple shipping method selection to OpenCart 3.0+. This requires modifying several core files (plus a database tweak) to handle storing and displaying multiple options. Here's a step-by-step breakdown:
First, update the shipping method selection template to use checkboxes instead of radio buttons. Edit catalog/view/theme/your_theme/template/checkout/shipping_method.twig:
{% if shipping_methods %} <p>{{ text_shipping_method }}</p> {% for shipping_method in shipping_methods %} <div class="checkbox"> <label> <input type="checkbox" name="shipping_method[]" value="{{ shipping_method.code }}" {% if shipping_method.code in selected %}checked="checked"{% endif %} /> {{ shipping_method.title }} - {{ shipping_method.text }} </label> </div> {% endfor %} {% else %} <p>{{ text_no_shipping }}</p> {% endif %}
Next, adjust the shipping method controller to handle multiple selections and store them in the session. Edit catalog/controller/checkout/shipping_method.php:
Update the Index Method
Replace the code handling selected shipping methods with this:
if (isset($this->request->post['shipping_method']) && is_array($this->request->post['shipping_method'])) { $selected_methods = []; // Match selected codes to full shipping method details foreach ($this->request->post['shipping_method'] as $code) { foreach ($this->session->data['shipping_methods'] as $method) { if ($method['code'] == $code) { $selected_methods[] = $method; break; } } } $this->session->data['shipping_method'] = $selected_methods; } // Pass selected codes to the template for checkbox pre-selection $data['selected'] = isset($this->session->data['shipping_method']) ? array_column($this->session->data['shipping_method'], 'code') : [];
Add Validation for Minimum One Selection
In the validate() method, add this check to ensure at least one method is selected:
if (!isset($this->request->post['shipping_method']) || empty($this->request->post['shipping_method'])) { $this->error['warning'] = $this->language->get('error_shipping'); }
We need a dedicated table to store multiple shipping methods per order. Run this SQL query in your database (adjust the prefix if you're not using oc_):
CREATE TABLE `oc_order_shipping_method` ( `order_shipping_method_id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL, `code` varchar(128) NOT NULL, `title` varchar(255) NOT NULL, `cost` decimal(15,4) NOT NULL, `tax_class_id` int(11) NOT NULL, `text` varchar(255) NOT NULL, PRIMARY KEY (`order_shipping_method_id`), KEY `order_id` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Edit catalog/model/checkout/order.php:
Save Multiple Shipping Methods
In the addOrder() method, after inserting the main order, add this loop to save each selected shipping method:
// Save multiple shipping methods if (isset($data['shipping_method']) && is_array($data['shipping_method'])) { foreach ($data['shipping_method'] as $method) { $this->db->query("INSERT INTO " . DB_PREFIX . "order_shipping_method SET order_id = '" . (int)$order_id . "', code = '" . $this->db->escape($method['code']) . "', title = '" . $this->db->escape($method['title']) . "', cost = '" . (float)$method['cost'] . "', tax_class_id = '" . (int)$method['tax_class_id'] . "', text = '" . $this->db->escape($method['text']) . "'"); } }
Retrieve Multiple Shipping Methods
In the getOrder() method, add this to fetch the saved shipping methods:
// Get multiple shipping methods $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_shipping_method WHERE order_id = '" . (int)$order_id . "'"); $order_info['shipping_methods'] = $query->rows;
Edit catalog/view/theme/your_theme/template/checkout/confirm.twig to display all selected shipping methods:
{% if shipping_methods %} <h2>{{ text_shipping_method }}</h2> <div class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <td>{{ column_shipping_method }}</td> <td>{{ column_cost }}</td> </tr> </thead> <tbody> {% for method in shipping_methods %} <tr> <td>{{ method.title }}</td> <td>{{ method.text }}</td> </tr> {% endfor %} </tbody> </table> </div> {% endif %}
Don't forget to pass the shipping_methods data from the checkout controller to the template:
$data['shipping_methods'] = $this->session->data['shipping_method'];
Edit admin/view/template/sale/order_info.twig to show multiple shipping methods in the admin panel:
{% if order_info.shipping_methods %} <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">{{ text_shipping_methods }}</h3> </div> <div class="panel-body"> <table class="table table-bordered"> <thead> <tr> <td>{{ column_title }}</td> <td>{{ column_cost }}</td> </tr> </thead> <tbody> {% for method in order_info.shipping_methods %} <tr> <td>{{ method.title }}</td> <td>{{ method.text }}</td> </tr> {% endfor %} </tbody> </table> </div> </div> {% endif %}
Add the corresponding language string in admin/language/en-gb/sale/order.php:
$_['text_shipping_methods'] = 'Shipping Methods';
Update the checkout controller to sum the costs of all selected shipping methods. In catalog/controller/checkout/checkout.php, replace the single shipping cost reference with:
$shipping_total = 0; $shipping_tax = 0; foreach ($this->session->data['shipping_method'] as $method) { $shipping_total += $method['cost']; // Calculate tax for each method $tax_rates = $this->tax->getRates($method['cost'], $method['tax_class_id']); foreach ($tax_rates as $tax) { $shipping_tax += $tax['amount']; } } // Add to total calculations $this->session->data['total'] += $shipping_total + $shipping_tax;
- Use OCmod/VQmod: To avoid losing changes when updating OpenCart, wrap these modifications in an OCmod XML file instead of editing core files directly.
- Testing: Thoroughly test the checkout flow, order creation, admin view, and email notifications to ensure everything works as expected.
- Tax Handling: Double-check tax calculations for multiple shipping methods, as tax rates may vary per method.
内容的提问来源于stack exchange,提问作者Tj Thouhid




