短代码返回的HTML未被浏览器解析执行,该如何解决?
解决WordPress短代码中HTML实体被转义的问题
嘿,我完全懂你现在的烦恼——短代码里banner消息的HTML变成了一堆<a>这样的实体字符,没法正常渲染成可点击的链接是吧?其实问题出在HTML实体的解码环节,你用的stripslashes只能处理反斜杠转义,对付不了这类HTML实体字符。
问题根源
你的banner_msg从数据库取出时,里面的HTML标签已经被转换成了实体编码(比如<a>变成<a>),而stripslashes只能去掉字符串里的反斜杠,没法把这些实体转回到原本的HTML标签,所以浏览器就把它们当成普通文本显示了。
修复方案
你只需要在处理$msg的时候,加上html_entity_decode()函数,把实体字符解码成正常的HTML标签就行。另外,如果这个消息是用户输入的内容,最好再用wp_kses()过滤一下允许的标签,避免XSS安全风险。
修改你代码里处理$msg的部分:
$msg = stripslashes($booklist[0]->banner_msg); $msg = html_entity_decode($msg); // 新增:解码HTML实体 $msg = str_replace("\n", "<br>", $msg); // 可选但推荐:过滤允许的HTML标签,提升安全性 $allowed_tags = array( 'a' => array( 'href' => array(), 'target' => array() ), 'br' => array(), 'em' => array(), 'strong' => array() ); $msg = wp_kses($msg, $allowed_tags);
完整修改后的代码片段
这里是调整后的generate_booklist_jumbo函数核心部分,我还顺手修正了几个小细节:
function generate_booklist_jumbo($atts) { $a = shortcode_atts( array( 'category' => 'Upcoming', 'name' => '', 'list_order' => 'DESC' ), $atts ); $listOrder = $a['list_order']; $booklist = null; if($a['name'] !== '') { $second_db = new wpdb(DB_USER, DB_PASSWORD, "saic3_LibraryIndex", DB_HOST); $query = "SELECT * FROM `LibraryList` WHERE `list_name` = %s ORDER BY date_created %s LIMIT 1"; $booklist = $second_db->get_results( $second_db->prepare( $query, $a['name'], $listOrder) ); } else if($a['category'] !== "") { $cat = $a['category']; $second_db = new wpdb(DB_USER, DB_PASSWORD, "saic3_LibraryIndex", DB_HOST); $query = "SELECT ll.* FROM LibraryListCategory llc INNER JOIN LibraryListCategoryList llcl ON llc.category_id = llcl.fk_category_id INNER JOIN LibraryList ll ON llcl.fk_list_id = ll.list_id WHERE llc.name= %s ORDER BY ll.date_created %s LIMIT 1"; $booklist = $second_db->get_results( $second_db->prepare($query, $cat, $listOrder) ); } if ($booklist!=null) { $booklist[0]->list_name = stripslashes($booklist[0]->list_name); $code = strval($booklist[0]->list_type_code); $msg = stripslashes($booklist[0]->banner_msg); $msg = html_entity_decode($msg); // 解码HTML实体 $msg = str_replace("\n", "<br>", $msg); // 安全过滤允许的标签 $allowed_tags = array( 'a' => array('href' => array(), 'target' => array()), 'br' => array(), 'strong' => array(), 'em' => array() ); $msg = wp_kses($msg, $allowed_tags); switch($code) { case "1": $link = "/booklist-details/".$booklist[0]->fk_list_id; break; case "2": $link = "/booklist-dvd-details/".$booklist[0]->fk_list_id; break; case "3": $link = "/booklist-audio-details/".$booklist[0]->fk_list_id; break; default: $link = "#"; // 加默认值避免无匹配时出错 break; } $content = '<div class="bootstrap-container"><div class="row"><div class="col-md-12"><div class="jumbotron container-fluid" style="height: 600px; width: 100%; background: url('.$booklist[0]->image_url.') no-repeat center center; background-size: cover;">'; $content.= '<a href="'.$link.'" target="_blank" ><h2 class="book-feat-title center-block">'.$booklist[0]->list_name.'</h2></a><p class="book-feat-msg">'.$msg.'</p>'; $content.= '</div></div></div></div>'; } else { $content="<h4>no booklist records</h4>"; } if(isset($second_db)) { // 避免未定义$second_db时报错 $second_db->close(); } return $content; } add_shortcode('booklist_jumbo','generate_booklist_jumbo');
额外提示
- 我修正了代码里几个小问题:比如原来的
$bookOrder变量没用到的笔误;给switch加了默认值避免$link未定义;还有判断$second_db是否存在再关闭,防止空指针错误。 - 如果你不确定数据库里的内容为什么会被实体编码,可以检查一下数据存入时的代码,是不是用了
esc_html()这类函数——如果是,以后存入可以改用wp_kses_post()保留安全HTML,这样取出来就不用额外解码了。
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

