开发WooCommerce众筹插件调用wc_get_product报错如何解决?
问题根因
两个报错本质都是WooCommerce核心函数调用时机太早导致:
- 你的插件加载顺序优先于WooCommerce,直接调用
wc_get_product()时函数还未被定义 - 手动引入WooCommerce主文件后,调用函数时WooCommerce还未完成初始化流程,触发官方的时机校验错误
- 额外问题:SQL查询返回的是对象,你直接将对象传入
wc_get_product()而非对象下的product_id属性,也会导致调用失败
修复步骤
1. 修改主插件文件
调整代码逻辑,等WooCommerce初始化完成后再加载功能代码,同时增加WooCommerce未激活的容错提示,代码如下:
<?php /** * Plugin Name: xxx * Plugin URI: xxx * Description: xxx * Version: xxx * Author: xxx.com * Author URI: xxx */ defined( 'ABSPATH' ) or die( 'Plugin file cannot be accessed directly.' ); // 校验WooCommerce是否激活 add_action( 'plugins_loaded', 'cfdg_check_woocommerce_active' ); function cfdg_check_woocommerce_active() { if ( ! class_exists( 'WooCommerce' ) ) { add_action( 'admin_notices', 'cfdg_woocommerce_missing_notice' ); return; } // WooCommerce已激活,加载功能文件、注册后台菜单 require(dirname(__FILE__).'/shortcodes.php'); add_action("admin_menu","cfdg_add_admin_menu"); } // WooCommerce未激活的后台提示 function cfdg_woocommerce_missing_notice() { ?> <div class="notice notice-error"> <p>众筹插件需要先安装并启用WooCommerce才能正常使用。</p> </div> <?php } function cfdg_add_admin_menu(){ add_menu_page("Crowdfunding","Crowdfunding", "manage_options", "cfdg-admin", "cfdg_add_page", "dashicons-money"); } function cfdg_add_page(){ require (dirname(__FILE__).'/adminmenu.php'); } ?>
2. 修改shortcodes.php文件
取消全局作用域的函数调用,将已筹金额计算逻辑放到短码回调中执行,同时修复参数传递错误,代码如下:
<?php $targetMoney = 30000; function cfdg_getEarnedMoney() { global $wpdb; $cdfg_money_to_return = 0; // 替换硬编码的表前缀为动态获取,适配自定义表前缀的站点 $sql = $wpdb->prepare('SELECT ml.product_id FROM %i AS pl JOIN %i AS ml ON pl.product_id = ml.product_id JOIN %i AS wp ON wp.ID = pl.order_id WHERE LOCATE("crowdfunding",sku) AND (wp.post_status = "wc-processing" OR wp.post_status = "wc-completed");', $wpdb->prefix . 'wc_order_product_lookup', $wpdb->prefix . 'wc_product_meta_lookup', $wpdb->posts ); $results = $wpdb->get_results($sql); if(!$results) return 0; foreach($results as $res){ // 传入查询到的product_id属性,而非整个结果对象 $cdfg_produkcik = wc_get_product($res->product_id); if(!$cdfg_produkcik) continue; // 增加商品不存在的容错 $cdfg_product_price= $cdfg_produkcik->get_price(); $cdfg_money_to_return += floatval($cdfg_product_price); } return $cdfg_money_to_return ; } //PROGRESS BAR add_shortcode('cfdg_progress_bar', 'cfdg_func_progress_bar'); function cfdg_func_progress_bar(){ global $targetMoney; // 在短码调用时才计算已筹金额,此时WooCommerce已完成初始化 $earnedMoney = cfdg_getEarnedMoney(); // 短码回调需return内容而非直接echo,避免输出位置错乱 return "Earned: ".$earnedMoney." from: ".$targetMoney." required"; } //END OF PROGRESS BAR ?>
其他优化建议
- 已筹金额计算可增加缓存逻辑,避免每次短码渲染都查库,降低数据库压力
- 金额输出可使用
wc_price()函数格式化,适配WooCommerce的货币设置 - 可以在插件后台增加目标金额的配置项,替代硬编码的30000数值
内容的提问来源于stack exchange,提问作者ErykNN
相关产品推荐
相关产品推荐

