PAYATHON 2026

OpenCart Payment plugin 报 render() 未定义错误

支付小周

结论

这是典型的 OpenCart 版本 API 混用问题。

当前控制器采用的是 OpenCart 1.5 的渲染方式:

$this->data
$this->template
$this->children
$this->render()

实际运行环境很可能是 OpenCart 2.x 或 3.x。这些版本通常不再通过 $this->render() 输出页面,而是把数据放入 $data,再调用:

$this->response->setOutput(
    $this->load->view('payment/cipg_sim.tpl', $data)
);

所以,只把 $this->data 替换为 $data 并不能解决问题。代码末尾仍会调用不存在的 $this->render(),页面也就无法正常输出。如果服务器关闭了 PHP 错误显示,浏览器中可能只会出现空白页。

OpenCart 2.x 的修改方法

先把控制器中的所有:

$this->data['key']

改为:

$data['key']

然后删除旧版的渲染配置:

$this->template = 'payment/cipg_sim.tpl';

$this->children = array(
    'common/header',
    'common/footer'
);

$this->response->setOutput($this->render());

改用 OpenCart 2.x 的写法:

$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['footer'] = $this->load->controller('common/footer');

$this->response->setOutput(
    $this->load->view('payment/cipg_sim.tpl', $data)
);

控制器的主要结构可以写成:

<?php
class ControllerPaymentCipgSim extends Controller
{
    private $error = array();

    public function index()
    {
        $this->load->language('payment/cipg_sim');
        $this->document->setTitle(
            $this->language->get('heading_title')
        );

        $this->load->model('setting/setting');

        if (
            $this->request->server['REQUEST_METHOD'] == 'POST'
            && $this->validate()
        ) {
            $this->model_setting_setting->editSetting(
                'cipg_sim',
                $this->request->post
            );

            $this->session->data['success'] =
                $this->language->get('text_success');

            $this->response->redirect(
                $this->url->link(
                    'extension/payment',
                    'token=' . $this->session->data['token'],
                    true
                )
            );
        }

        $data['heading_title'] =
            $this->language->get('heading_title');

        $data['text_enabled'] =
            $this->language->get('text_enabled');

        $data['text_disabled'] =
            $this->language->get('text_disabled');

        if (isset($this->request->post['cipg_sim_status'])) {
            $data['cipg_sim_status'] =
                $this->request->post['cipg_sim_status'];
        } else {
            $data['cipg_sim_status'] =
                $this->config->get('cipg_sim_status');
        }

        $data['action'] = $this->url->link(
            'payment/cipg_sim',
            'token=' . $this->session->data['token'],
            true
        );

        $data['cancel'] = $this->url->link(
            'extension/payment',
            'token=' . $this->session->data['token'],
            true
        );

        $data['header'] =
            $this->load->controller('common/header');

        $data['column_left'] =
            $this->load->controller('common/column_left');

        $data['footer'] =
            $this->load->controller('common/footer');

        $this->response->setOutput(
            $this->load->view('payment/cipg_sim.tpl', $data)
        );
    }

    protected function validate()
    {
        if (
            !$this->user->hasPermission(
                'modify',
                'payment/cipg_sim'
            )
        ) {
            $this->error['warning'] =
                $this->language->get('error_permission');
        }

        return !$this->error;
    }
}

模板需要直接使用控制器传入的变量,例如:

<?php echo $header; ?>
<?php echo $column_left; ?>

<div id="content">
    <h1><?php echo $heading_title; ?></h1>
</div>

<?php echo $footer; ?>

如果模板仍然依赖旧版 $this->data 或旧版子控制器输出方式,即使控制器已经修改,页面仍可能空白或缺少布局。

如果使用的是 OpenCart 3.x

OpenCart 3.x 默认使用 Twig,因此控制器写法和模板路径还要进一步调整。常见写法如下:

$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['footer'] = $this->load->controller('common/footer');

$this->response->setOutput(
    $this->load->view('extension/payment/cipg_sim', $data)
);

模板通常位于:

admin/view/template/extension/payment/cipg_sim.twig

后台令牌一般也要从:

token

改为:

user_token

例如:

$data['action'] = $this->url->link(
    'extension/payment/cipg_sim',
    'user_token=' . $this->session->data['user_token'],
    true
);

OpenCart 2.0、2.2、2.3 和 3.x 的扩展目录、路由及模板规则不完全相同,不能只修改一个渲染调用。应参照当前安装版本自带的支付模块,使用相同的目录结构和控制器写法进行迁移。

为什么替换成 $data 后是空白页

$this->data 和 $data 不能单独互换,因为它们属于不同的页面渲染流程。

旧版流程大致如下:

$this->data['heading_title'] = '...';
$this->template = 'payment/cipg_sim.tpl';
$this->response->setOutput($this->render());

新版流程则是:

$data['heading_title'] = '...';

$this->response->setOutput(
    $this->load->view('payment/cipg_sim.tpl', $data)
);

如果只替换变量,却保留:

$this->render()

控制器仍然会调用不存在的方法。反过来,如果实际运行的是 OpenCart 1.5,却把数据改为局部变量 $data,旧版 render() 不会自动读取该变量,模板同样拿不到数据。

空白页通常不表示错误已经消失,而是 PHP 关闭了 display_errors。可以查看:

system/storage/logs/error.log

部分旧版本的日志可能位于:

system/logs/error.txt

也可以到 OpenCart 后台的错误日志页面查看具体异常。

还需要检查控制器名称

错误信息中的类名是:

ControllerPaymentStanbic

代码使用的模块名和路由却是:

cipg_sim
payment/cipg_sim

这表明实际加载的控制器、文件名、类名和路由可能没有统一。以旧式支付模块目录为例,各项名称通常需要保持对应:

文件:admin/controller/payment/cipg_sim.php
类名:ControllerPaymentCipgSim
路由:payment/cipg_sim
语言:payment/cipg_sim
模板:payment/cipg_sim.tpl

如果文件实际是:

admin/controller/payment/stanbic.php

类名就应与文件名对应:

class ControllerPaymentStanbic extends Controller

相关路由、语言文件和模板路径也应统一使用 stanbic,或者全部改为 cipg_sim。两个模块标识不能混用。

其他代码问题

代码开头显示为:

load->language('payment/cipg_sim');

如果源文件中确实是这样,而不是复制时漏掉了内容,应改为:

$this->load->language('payment/cipg_sim');

另外,validate() 中的权限检查被注释掉了。支付模块保存配置时应恢复权限验证:

if (!$this->user->hasPermission('modify', 'payment/cipg_sim')) {
    $this->error['warning'] =
        $this->language->get('error_permission');
}

也不建议直接拼接 HTTPS_SERVER:

HTTPS_SERVER . 'index.php?route=...'

应使用当前版本支持的 $this->url->link() 和 $this->response->redirect(),以便正确处理后台地址、HTTPS、令牌和 URL 编码。

解决这个问题不能只替换 $this->data。控制器、模板、路由和令牌处理都需要按当前 OpenCart 版本的扩展结构完整迁移。

备注:内容仅供参考。