WooCommerce开发:使用esc_html时如何正常渲染带CSS的HTML标签
问题根源
esc_html()的设计逻辑就是把所有HTML特殊字符(<、>、引号等)转义为字符实体,浏览器会把转义后的内容识别为纯文本,不会解析为HTML标签,自然也不会加载绑定的CSS样式。你遇到的标签直接输出、样式失效是这个函数的正常表现,不是代码bug。
WordPress安全规范从来不是要求所有输出变量统一套esc_html(),必须根据变量的输出场景选择对应的转义函数,错用函数就会导致渲染异常。
对应场景的正确转义规则
- 输出无HTML标签的纯文本(比如日期、订单号、状态名、商品名称这类普通字符串):用
esc_html(),你代码里的$date_created本身是d/m/Y格式的纯日期,正确使用esc_html()不会影响样式。 - 输出HTML属性内的URL值(比如
href、src属性里的链接):用esc_url(),你代码里的订单详情链接$view_order、商品下载链接都属于这类。 - 输出系统生成的可信HTML内容(比如WooCommerce返回的带格式的订单金额、商品图片、分页HTML这类包含合法标签和样式的内容):用
wp_kses_post(),这个函数会过滤掉恶意脚本等危险内容,同时保留合法的HTML标签、属性和样式。 - 输出普通HTML属性值(比如
title、class里的动态内容):用esc_attr()。
代码修正示例
你之前测试的a标签案例属于典型的函数错用,不能把整个HTML标签字符串丢进esc_html(),要拆分动态部分分别转义:
// 错误写法:整个a标签被转义为纯文本 // echo esc_html( '<a href="http://www.example.com/">A link</a>' ); // 正确写法:静态标签保留,动态内容按位置转义 printf( '<a href="%s" target="_blank">%s</a>', esc_url( 'http://www.example.com/' ), // 链接用esc_url esc_html( 'A link' ) // 链接文本用esc_html );
针对你提供的orders.php模板,核心需要修改的点:
- 把原来整块字符串拼接输出的写法改成PHP与HTML混写,只对动态变量做转义,静态写死的HTML标签不需要处理
- 修正你代码里
target=”_blank”的全角引号问题,换成英文半角引号否则属性不生效 - 每个动态变量按输出场景匹配对应转义函数
修正后的完整模板代码如下:
<?php defined( 'ABSPATH' ) || exit; do_action( 'woocommerce_before_account_orders', $has_orders ); ?> <div class="orders-container"> <table class="table_orders heading"> <tr> <td class="product_number"><?php esc_html_e( 'Ordine', 'your-theme' ); ?></td> <td class="product_name"><?php esc_html_e( 'Prodotto', 'your-theme' ); ?></td> <td class="product_data"><?php esc_html_e( 'Data', 'your-theme' ); ?></td> <td class="product_price"><?php esc_html_e( 'Totale', 'your-theme' ); ?></td> <td class="product_status"><?php esc_html_e( 'Stato', 'your-theme' ); ?></td> <td class="product_action"><?php esc_html_e( 'File', 'your-theme' ); ?></td> </tr> </table> <?php if ( $has_orders ) { foreach ( $customer_orders->orders as $customer_order ) { $order = wc_get_order( $customer_order ); $items = $order->get_items(); $orders_id = $order->get_id(); $status = wc_get_order_status_name( $order->get_status() ); $date_created = $order->get_date_created()->date('d/m/Y'); $order_total = $order->get_formatted_order_total(); foreach ( $items as $item ) { $product_name = $item->get_name(); $product = $item->get_product(); $order_img = ''; if( $product instanceof WC_Product ){ $order_img = $product->get_image(); } $download_button = ''; $downloads = $order->get_downloadable_items(); if(is_array($downloads)) { foreach($downloads as $download_item){ $download_button .= sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( $download_item['download_url'] ), esc_html__( 'Download', 'woocommerce' ) ); } } $view_order = $order->get_view_order_url(); ?> <table class="table_orders"> <tr class="table_row_items"> <td class="product_number"> <span class="mobile title"><?php esc_html_e( 'Ordine', 'your-theme' ); ?></span> <span>#<?php echo esc_html( $orders_id ); ?></span> </td> <td class="product_name"> <span class="mobile title"><?php esc_html_e( 'Prodotto', 'your-theme' ); ?></span> <a href="<?php echo esc_url( $view_order ); ?>"><?php echo esc_html( $product_name ); ?></a> </td> <td class="product_data"> <span class="mobile title"><?php esc_html_e( 'Data', 'your-theme' ); ?></span> <span><?php echo esc_html( $date_created ); ?></span> </td> <td class="product_price"> <span class="mobile title"><?php esc_html_e( 'Prezzo', 'your-theme' ); ?></span> <span><?php echo wp_kses_post( $order_total ); ?></span> </td> <td class="product_status"> <span class="mobile title"><?php esc_html_e( 'Stato', 'your-theme' ); ?></span> <span><?php echo esc_html( $status ); ?></span> </td> <td class="product_action"> <span class="mobile title"><?php esc_html_e( 'File', 'your-theme' ); ?></span> <a target="_blank" href="<?php echo esc_url( $view_order ); ?>"> <?php esc_html_e( 'Visualizza', 'your-theme' ); ?> <i class="fa-duotone fa-eye"></i> </a> </td> </tr> </table> <?php if( $download_button ) { printf( '<div class="container_orders_download">%s</div>', wp_kses_post( $download_button ) ); } } } ?> <div class="container-pagination"> <?php $args = array( 'base' => esc_url( wc_get_endpoint_url( 'orders') ) . '%_%', 'format' => '%#%', 'total' => $customer_orders->max_num_pages, 'current' => $current_page, 'show_all' => false, 'end_size' => 3, 'mid_size' => 3, 'prev_next' => true, 'prev_text' => '<i class="fa-solid fa-angle-left"></i>', 'next_text' => '<i class="fa-solid fa-angle-right"></i>', 'type' => 'plain', 'add_args' => false, 'add_fragment' => '' ); echo wp_kses_post( paginate_links($args) ); ?> </div> <?php } else { ?> <div class="msg_orders"><?php esc_html_e( 'La tua cronologia ordini è vuota!', 'your-theme' ); ?></div> <?php } do_action( 'woocommerce_after_account_orders', $has_orders ); ?> </div>
内容的提问来源于stack exchange,提问作者Snorlax
相关产品推荐
相关产品推荐

