WooCommerce“我的账户”页面中实现订单关联的自定义菜单与动态内容路由

1次阅读

WooCommerce“我的账户”页面中实现订单关联的自定义菜单与动态内容路由

本文详解如何在 WooCommerce 的 My Account 页面正确注册带参数的自定义账户端点(如 /my-account/custom-menu/19651/),并通过查询变量精准捕获订单 ID,渲染对应订单状态的专属内容,避免默认主菜单内容误显。

本文详解如何在 woocommerce 的 my account 页面正确注册带参数的自定义账户端点(如 `/my-account/custom-menu/19651/`),并通过查询变量精准捕获订单 id,渲染对应订单状态的专属内容,避免默认主菜单内容误显。

在 WooCommerce 中扩展“我的账户”(My Account)页面功能时,常需为特定订单添加定制操作入口(如“查看详情”“申请售后”等),并跳转至携带订单 ID 的专属子页面(例如 /my-account/custom-menu/19651/)。但许多开发者会遇到一个典型问题:URL 虽然正确生成,页面却始终显示默认的主菜单内容(如“Main menu content”),而非按订单 ID 动态渲染的内容。根本原因在于——WooCommerce 的端点(endpoint)机制本身不自动解析路径中的数字参数;它仅将 custom-menu 识别为查询变量,而 /19651/ 这部分不会被自动映射为 $wp->query_vars[‘custom-menu’] 的值。

要解决该问题,必须结合 wordpress 的重写规则、查询变量注册与端点内容回调三者协同工作,并在回调函数中主动从全局 $wp 对象提取路径参数。以下是完整、可直接部署的专业级实现方案:

✅ 正确注册带参数支持的端点

首先,确保端点注册支持路径层级匹配(即允许 /custom-menu/12345/ 这类结构)。关键在于使用 EP_PAGES | EP_ROOT 并避免在 rewrite_endpoint() 中调用 flush_rewrite_rules()(该函数仅应在插件激活时执行一次,否则严重拖慢请求):

// ✅ 推荐:仅在插件激活时刷新重写规则 register_activation_hook( __FILE__, [ $this, 'flush_rewrite_on_activation' ] ); public function flush_rewrite_on_activation() {     $this->rewrite_endpoint();     flush_rewrite_rules(); }  public function rewrite_endpoint() {     add_rewrite_endpoint( 'custom-menu', EP_PAGES | EP_ROOT ); }

⚠️ 注意:flush_rewrite_rules() 绝对不可放在 init 钩子中反复执行,否则每次页面加载都会触发重写规则重建,导致性能崩溃。

✅ 正确注册查询变量并解析路径参数

add_new_query_vars() 仅声明变量名,真正提取路径中数字的关键在于端点内容回调函数:

public function content_custom_menu() {     global $wp;      // ✅ 正确方式:从 $wp->request 或 $wp->query_vars 中提取路径参数     $order_id = 0;      // 方法一:优先尝试从 query_vars(需配合 add_rewrite_rule 才能精确映射)     if ( isset( $wp->query_vars['custom-menu'] ) && is_numeric( $wp->query_vars['custom-menu'] ) ) {         $order_id = absint( $wp->query_vars['custom-menu'] );     }      // 方法二(更鲁棒):直接解析当前请求路径(推荐用于简单场景)     elseif ( ! empty( $wp->request ) ) {         $parts = explode( '/', trim( $wp->request, '/' ) );         $last_part = end( $parts );         if ( is_numeric( $last_part ) && $parts[0] === 'custom-menu' ) {             $order_id = absint( $last_part );         }     }      if ( $order_id > 0 ) {         $order = wc_get_order( $order_id );         if ( $order && $order->get_customer_id() === get_current_user_id() ) {             // ✅ 渲染订单专属内容(按状态分支处理)             switch ( $order->get_status() ) {                 case 'processing':                     echo '<h3>订单处理中</h3><p>您的订单正在打包发货,请耐心等待物流更新。</p><div class="aritcle_card flexRow">                                                         <div class="artcardd flexRow">                                                                 <a class="aritcle_card_img" href="/ai/865" title="酷表ChatExcel"><img                                                                                 src="https://img.php.cn/upload/ai_manual/001/503/042/68b6d62c31469779.png" alt="酷表ChatExcel"  onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>                                                                 <div class="aritcle_card_info flexColumn">                                                                         <a href="/ai/865" title="酷表ChatExcel">酷表ChatExcel</a>                                                                         <p>北大团队开发的通过聊天来操作Excel表格的AI工具</p>                                                                 </div>                                                                 <a href="/ai/865" title="酷表ChatExcel" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>                                                         </div>                                                 </div>';                     break;                 case 'completed':                     echo '<h3>订单已完成</h3><p>感谢您的购买!您可在此下载电子发票或评价商品。</p>';                     break;                 default:                     echo '<h3>订单详情</h3>' . wc_get_formatted_order_details( $order );             }         } else {             wc_print_notice( '无效的订单或无权访问此订单。', 'error' );         }     } else {         // ✅ 显示自定义菜单主页面(无参数时)         echo '<h3>我的定制服务</h3><p>此处展示所有可用的个性化操作入口。</p>';         $customer_orders = wc_get_orders([             'customer' => get_current_user_id(),             'status'   => array_map( 'wc_get_order_status_name', wc_get_order_statuses() ),             'limit'    => 5,         ]);         foreach ( $customer_orders as $order ) {             $url = wc_get_account_endpoint_url( 'custom-menu' ) . $order->get_id() . '/';             echo '<p><a href="' . esc_url( $url ) . '">→ 查看订单 #' . $order->get_id() . '</a></p>';         }     } }

✅ 修正订单操作按钮的 URL 生成逻辑

原代码中 wc_get_account_endpoint_url( ‘custom-menu’ ) . $order->get_id() 生成的是 /my-account/custom-menu19651(缺少斜杠),会导致重写规则无法匹配。必须确保末尾有 /

public function order_custom_content_display_button( $actions, $order ) {     // ✅ 关键修正:URL 必须以 '/' 结尾,才能匹配 EP_PAGES 规则     $url = wc_get_account_endpoint_url( 'custom-menu' ) . $order->get_id() . '/';     $actions['custom'] = [         'url'  => esc_url_raw( $url ),         'name' => __( '定制操作', 'your-text-domain' )     ];     return $actions; }

✅ 最终注意事项与最佳实践

  • 权限校验不可省略:务必通过 get_current_user_id() 与 $order->get_customer_id() 校验当前用户是否拥有该订单访问权,防止越权访问。
  • 模板复用建议:复杂内容建议使用 wc_get_template() 加载独立模板文件(如 myaccount/custom-menu-order.php),提升可维护性。
  • 国际化支持:所有前端文本必须使用 __() 或 _e() 包裹,并在 load_plugin_textdomain() 中加载语言包。
  • 调试技巧:开发时可临时打印 var_dump( $wp->request, $wp->query_vars ); 确认路径解析是否符合预期。

通过以上结构化实现,你将获得一个健壮、安全且可扩展的订单关联自定义菜单系统——URL 形如 /my-account/custom-menu/19651/ 将准确触发对应订单的专属内容,彻底告别“总是显示主菜单”的困扰。

text=ZqhQzanResources