Đa số các plugin toc+ hay table of content đang có đều không hỗ trợ mục lục cho mô tả danh mục sản phẩm nên mình đã tự viết + tham khảo thêm chat GPT, cuối cùng đã viết được mục lục cho mô tả danh mục sản phẩm rồi. Chia sẻ cùng các bạn sử dụng luôn nếu cần nhé
Các bạn chỉ cần copy đoạn code sau vào functions.php của theme đang sử dụng (wp-content/themes/{your-theme}/functions.php) là được. Áp dụng cho mô tả danh mục sản phẩm với mọi theme có sử dụng Woocommerce nhé
/*
* Thêm mục lục cho mô tả danh mục sản phẩm
* Author: levantoan.com
*/
add_action('wp_footer', 'devvn_add_heading_style');
function devvn_add_heading_style(){
?>
<style>
.devvn_heading_wrap {
background: rgba(243,243,243,0.95);
border: 1px solid rgb(197 197 197);
width: 100%;
color: #333;
margin: 0 0 20px 0;
padding: 0;
}
.devvn_heading_title {
padding: 10px 15px;
background: #c5c5c5;
position: relative;
cursor: pointer;
}
.devvn_heading_wrap > ol {
margin: 10px 0 10px 33px;
}
.devvn_heading_wrap > ol > li {
margin: 0;
padding: 0;
}
.devvn_heading_wrap > ol > li ul {
margin: 0;
padding: 0;
}
.devvn_heading_wrap > ol > li ul li {
margin: 0;
padding: 0;
list-style: none;
}
.devvn_heading_wrap > ol {
counter-reset: List;
}
.devvn_heading_wrap > ol > li {
counter-increment: List;
}
.devvn_heading_wrap > ol > li ul {
counter-reset: List;
}
.devvn_heading_wrap > ol > li ul li {
counter-increment: List;
}
.devvn_heading_wrap > ol > li ul li:before {
content: counters(List,".");
}
.devvn_heading_title strong {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgEAQAAACJ4248AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAACYktHRAAAqo0jMgAAAAlwSFlzAAAAYAAAAGAA8GtCzwAAAAd0SU1FB+cJBA8RMDu7ID0AAAKXSURBVFjD7ZVNSBtBGIa/mV1Nfw6BtgoVidp6KPbSZj20CppCL6WHeqhgTDZGCIJSUGOQlGiagElIicHUQ+qaQGx0D+mp0EOhPyAoQssuCqXXUkIoVKWtFamszfQQTKKbg4fJyTynmXkG3vmGbxiACqcd1PxMo9EmfD4Y6+kBRlGIThDktmAQIJsFAGhJVVef/eHxkOs8jxz19VRS7ZkM3BfF3y8mJ5H+y/Q04u32Yk+CIyPy3UgEAED/aGoKrblcZSnfEgphaO7tVV3LX7M5P+lSe1qQQbMZw+rBgcowipI/zM8SntoJFAUjQzyuuoFALJaf7Kk9NTZiMdTdzTBf342NEavJRAz7+8grCJIcjwMQktuFcWvd8HBWsFjQdkMDleD1dJp8W1y8yoTDZSuuwklBnL6qCgYmJuCi0QiMohBhfl5+E4kc9kAnYdnduNNJdDyPvtfUUEk9t7UFD0UROJ8PcVwgAOB0Ht0xNCRJ0SgAgP6j240Gvd6ylL/q92OAvr7j6+SD1Zqf7BSNadPe34/h9uFzK4DuFNbQeO5PKAv2bBbDtYUFlXiSSBROU8JTgqwlErkmlFwu8tZohH+KglyCIMmzs8VN+IcfHwfBYkEva2upBF/e3ISUKCLZ7y9XcRVODOokLLvb6nBAh9EIWFFIx9yc/CAWK/6MOG50FNw8D790Oiqp6+k03BDFK69DIcQ993ph3u0+smHKZpPu5b5hjnM6AQKBclRPbno8GD7bbCrzvmiNlPC0MNlsmIQxVgkDy+bzn5bwtGhnWYxuLS2phDuZzI8vlPCUQHvJJHP+8fLymbBGA5caG0nX9jZqCQal6MzMYRPWfVpZIW0YQ6qpCcW1WirJ9kyGDESjO6+O9V6FU8l/eGH2Ze896egAAAAASUVORK5CYII=) no-repeat left center;
background-size: 22px 22px !important;
padding-left: 32px;
text-transform: uppercase;
}
.devvn_heading_title::after {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgEAQAAACJ4248AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAACYktHRAAAqo0jMgAAAAlwSFlzAAAAYAAAAGAA8GtCzwAAAAd0SU1FB+cJBA8REu7bYdkAAAHLSURBVFjD7ZS9S8NAGId/l0a0QaiuDl3cXIScg2CrRQhSuruKf4GggthSN1P6KYKTi7vtVmIpQehgFzHFycmPQfBjakGpIsI5SEtr05qmaQXJD27J+949T94jAezYsQNggfE8FV2uQfGm2djYAuN5AOBoRZJeis/PIJWK+JBOUyoI/QJTKgjiYSbDz5TLL59PT7QiSYSK19cgk5O1JqYWCkQKBDStWrUazlRFIZLPV3/Ibm44oHn0RPL5mKooVk5CFw4AcLk4cheP/9xgpUR7OIC1RIK7KMdiKMqyngSQz08dj472AoeUzerB2dLenrYSjZJ68/vuLuaCwdZjzs7etvz+q+XXVzNwqIuLevCSvL4OAKRpk0USRuEtAlZIdAPXFehFolt4WwEzEmbgAMC1E9BGQiGsRiKtFY/HGc3lGr8Os3AAcKBDHk9OTydCw8O49HqbK273UHF+fnw/nXbf8rxZeMcraBqvmEiAbGy0ANRCAaj9M34Wk0mttLn529mGBACAHsgyjra3jfQaefNaHEaagE7XYR7elYARiW7hpkMPZJlSxhqXGEyl+g5ujHi+s0Ppx8f3CocHCq9PggrC7L3T+SdwO3b+Tb4AHn8FI1FdY6oAAAAASUVORK5CYII=) no-repeat center center;
width: 12px;
height: 12px;
background-size: 100% 100%;
right: 15px;
top: 50%;
margin-top: -6px;
content: "";
position: absolute;
transition: all .3s linear;
-moz-transition: all .3s linear;
-webkit-transition: all .3s linear;
}
.devvn_heading_wrap.active .devvn_heading_title::after {
transform: rotate(180deg);
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
}
</style>
<script>
(function ($){
$('body').on('click', '.devvn_heading_title', function (){
let thisBox = $(this).closest('.devvn_heading_wrap');
if(thisBox.hasClass('active')){
$('> ol', thisBox).slideUp();
}else{
$('> ol', thisBox).slideDown();
}
thisBox.toggleClass('active');
});
$('.devvn_heading_wrap a').on('click', function (){
let idElement = $(this).attr("href");
let top = $(idElement).offset().top;
$('html, body').animate({scrollTop:top-44}, 500 );
return false;
})
})(jQuery);
</script>
<?php
}
add_filter('woocommerce_taxonomy_archive_description_raw', 'devvn_auto_add_heading_ids');
function devvn_auto_add_heading_ids($content) {
$content = wp_kses_post( $content );
$dom = new DOMDocument();
if(!$content) return $content;
$dom->loadHTML(mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXPath($dom);
$headings = $xpath->query('//h2|//h3');
$table_content = array();
$h2 = 0;
foreach ($headings as $index => $heading) {
$headingText = $heading->textContent;
$id = sanitize_title($headingText);
$id = ensure_unique_id($id, $xpath, $index);
$heading->setAttribute('id', $id);
if($heading->tagName == 'h2') {
$h2++;
$table_content[$h2] = array(
'title' => $headingText,
'href' => '#'.$id,
);
}elseif($heading->tagName == 'h3') {
$table_content[$h2]['child'][] = array(
'title' => $headingText,
'href' => '#'.$id,
);
}
}
$newContent = $dom->saveHTML();
$table_content_out = '';
if($table_content){
ob_start();
?>
<div class="devvn_heading_wrap active">
<div class="devvn_heading_title">
<strong><?php _e('Mục lục', 'devvn');?></strong>
</div>
<ol>
<?php foreach ($table_content as $item):?>
<?php
$title = isset($item['title']) ? sanitize_text_field($item['title']) : '';
$href = isset($item['href']) ? esc_attr($item['href']) : '';
$child = isset($item['child']) ? (array) $item['child'] : array();
if(!$title) continue;
?>
<li><a href="<?php echo $href;?>" title="<?php echo $title;?>"><?php echo $title;?></a><?php if($child){?><ul><?php foreach ($child as $child_item):?>
<?php
$child_title = isset($child_item['title']) ? sanitize_text_field($child_item['title']) : '';
$child_href = isset($child_item['href']) ? esc_attr($child_item['href']) : '';
if(!$child_title) continue;
?>
<li>
<a href="<?php echo $child_href;?>" title="<?php echo $child_title;?>"><?php echo $child_title;?></a>
</li>
<?php endforeach;?></ul><?php }?></li>
<?php endforeach;?>
</ol>
</div>
<?php
$table_content_out = ob_get_clean();
}
return $table_content_out . $newContent;
}
if(!function_exists('ensure_unique_id')) {
function ensure_unique_id($id, $xpath, $index)
{
$existingIds = [];
$existingHeadings = $xpath->query('//h2[@id] | //h3[@id]');
foreach ($existingHeadings as $existingHeading) {
$existingId = $existingHeading->getAttribute('id');
$existingIds[] = $existingId;
}
if (in_array($id, $existingIds)) {
$i = 1;
$newId = $id . '-' . $i;
while (in_array($newId, $existingIds)) {
$i++;
$newId = $id . '-' . $i;
}
return $newId;
}
return $id;
}
}
Hiện tại code trên hỗ trợ cho thẻ H2 và H3 nha. Có style cơ bản rồi. Các bạn tự style lại cho đẹp nếu muốn nhé
Để duy trì blog nên mình có làm aff cho 1 số bên hosting. Nhưng dù aff mình cũng chọn 1 số nhà cung cấp uy tín về chất lượng và support nên các bạn cứ yên tâm nhé.
Nếu có mua hosting mà có trong list dưới đây các bạn click vào link trước khi mua để ủng hộ mình nhé. Mình cảm ơn nhiều
- Azdigi: Giá rẻ thì dùng gói Pro Gold Hosting còn chất lượng hơn thì em khuyên dùng Business Hosting. Có điều kiện thì lên VPS nhé
- Tino hosting
- iNet
- Nước ngoài thì Vultr
Chúc các bạn thành công!
- Bình luận