Tạo mục lục trong Oxygen Builder
MỤC LỤC
Tại sao tôi lại không dùng plugin tạo mục lục?
Đối với anh em "low tech" cứ phang plugin TOC cho nhanh, gọn, lẹ. Bản thân mình thì lại thích vọc vạch vì "mục lục" này cũng không phải gì to tát tuy nhiên để nó hoạt động tốt thì cũng cần phải cấu hình cho đúng.
Mình đã từng sử dụng TOC của Gutenberg. Mọi thứ đều tuyệt vời cho đến khi mình quyết định đổi plugin khác. Mình phải xóa block tạo mục lục cho từng bài viết, Ôi! trời ơi. May mắn là khi đó mình chỉ có tầm 10 bài viết thôi.
Từ ngày đó mình quyết đổi plugin nào có chức năng tự động tạo mục lục theo tiêu đề thẻ heading. Khổ nỗi không có cái nào làm hình hài lòng cả, cái nào xịn xịn thì phải trả phí.
Nhờ công nghệ AI như ChatGPT, Bard, Bing mà mình có thể tạo "TOC nhà làm".
Tạo mục lục như thế nào cho đúng?
Trước khi tạo TOC chúng ta cần hiểu rõ về cấu hình mục lục để chuẩn SEO, thân thiện với người dùng.
Anchor Link thân thiện
Có những plugin tạo mục lục tự động nhưng lại đặt cho các thẻ heading dạng id="section-1"
và link trỏ đến thẻ heading này là href="#section-1"
.
Vậy nên bạn cần lưu ý đến những tiểu tiết nhỏ này. Hiện tại có thể nhu cầu chưa nhiều cho vấn đề này.
Đây là một vài ví dụ link anchor chuẩn:
- Test thử link này trong trang của ARTRU.
- Link này trỏ đến "# Ẩn các menu không dùng" của WPcanban.
- Link này trỏ đến "# Table of Contents Title" của Rank Math.
Hiệu ứng cuộn mượt (Smooth Scroll)
Giúp cho người dùng cảm thấy thoải mái, thích mắt hơn.
Đặc biệt hữu ích khi sử dụng url có #hashtag được gửi từ trang khác giúp cho người dùng biết được mục #hashtag này đang nằm ở đâu của bài viết.
Sticky (Ghim) mục lục
Đây cũng là tính năng tốt cho người dùng. Khi đọc bài viết họ có thể biết đang đọc đến đâu của bài viết thay vì phải kéo lên đầu trang để check lại phần mục lục.
Hiện tại mình chưa sử dụng tính năng này cho website. Sẽ cập nhật nếu có thay đổi.
Hướng dẫn tạo mục lục
Các mã này mình áp dụng cho trình kéo thả Oxygen Builder. Bạn cũng có thể áp dụng cho các Builder, Theme khác.
Code tạo mục lục tự động
Mã bên dưới có chức năng:
- Tạo các thẻ
<a>
theo h2-h6 trong nội dung bài viết. - Thêm thuộc tính
href="#"
vào các thẻ<a>
. - Sắp xếp các thẻ
<a>
theo quy tắc đệ quy<ol> <li>
Đặt Mã PHP này đặt vào vị trí bạn muốn hiển thị mục lục.
/* MÃ PHP TẠO MỤC LỤC TỰ ĐỘNG H2-H6. SỬ DỤNG get_the_content() */
function generate_toc($content)
{
preg_match_all('/<h([2-6]).*?>(.*?)<\/h\1>/', $content, $matches, PREG_SET_ORDER);
$toc = '<ol id="tocList">';
$current_level = 2;
foreach ($matches as $match)
{
$level = $match[1];
$heading = $match[2];
$id = sanitize_title($heading);
if ($level > $current_level)
{
$toc .= str_repeat('<ol>', $level - $current_level) . '<li><a href="#' . $id . '">' . $heading . '</a>';
}
else if ($level < $current_level)
{
$toc .= str_repeat('</li></ol>', $current_level - $level) . '</li><li><a href="#' . $id . '">' . $heading . '</a>';
}
else
{
$toc .= '</li><li><a href="#' . $id . '">' . $heading . '</a>';
}
$current_level = $level;
}
$toc .= str_repeat('</li></ol>', $current_level - 2);
$content = '<div id="tocDiv"><p>MỤC LỤC</p>' . $toc . '</div>';
return $content;
};
$content = get_the_content();
$content_with_toc = generate_toc($content);
echo $content_with_toc;
Sau khi áp dụng code ở trên, mục lục sẽ có cấu trúc như sau:
<div id="tocDiv">
<p>MỤC LỤC</p>
<ol id="tocList">
<!-- Danh sách mục lục -->
<li></li>
<li></li>
<li></li>
</ol>
</div>
Thêm thuộc tính "id" các thẻ heading
Làm việc này nhằm mục đích khi người dùng click vào link ở mục lục thì sẽ di chuyển đến đúng thẻ heading đó.
Mã PHP để thêm id cho các thẻ Heading nên đặt vào tệp function.php
trong child theme hoặc tạo thêm mu-plugins
hoặc có thể cùng vị trí mà bạn đặt mã tạo mục lục ở trên nhưng mình không khuyến khích cách này.
/* MÃ PHP TẠO THUỘC TÍNH ID CHO CÁC THẺ HEADING H2-H6 TRONG NỘI DUNG BÀI VIẾT */
function prefix_heading_ids($content)
{
$pattern = '#(?P<full_tag><(?P<tag_name>h\d)(?P<tag_extra>[^>]*)>(?P<tag_contents>[^<]*)</h\d>)#i';
if (preg_match_all($pattern, $content, $matches, PREG_SET_ORDER))
{
$find = array();
$replace = array();
foreach ($matches as $match)
{
if (strlen($match['tag_extra']) && false !== stripos($match['tag_extra'], 'id='))
{
continue;
}
$find[] = $match['full_tag'];
$id = sanitize_title($match['tag_contents']);
$id_attr = sprintf(' id="%s"', $id);
$replace[] = sprintf('<%1$s%2$s%3$s>%4$s</%1$s>', $match['tag_name'], $match['tag_extra'], $id_attr, $match['tag_contents']);
}
$content = str_replace($find, $replace, $content);
}
return $content;
}
add_filter('the_content', 'prefix_heading_ids');
Mã CSS sắp xếp đệ quy cho mục lục
Dưới đây là mã CSS sắp xếp đệ quy cho mục lục được bọc trong <div> có id="tocDiv" và <ol> có id="tocList".
#tocDiv {
width: 100%;
border-radius: 10px;
box-shadow: 5px 5px 10px 5px rgba(0, 0, 0, 0.5);
overflow: hidden;
margin: 50px 0px 50px 0px;
}
#tocDiv p {
font-weight: bold;
text-align: center;
display: block;
}
#tocDiv ol {
list-style: none;
}
#tocList {
padding-left: 20px;
white-space: nowrap;
overflow-x: auto;
padding-bottom: 20px;
margin-bottom: 0px;
}
#tocList a {
margin-right: 10px;
}
#tocList ol {
padding-left: 20px;
}
#tocList {
counter-reset: item;
}
#tocList>li:before {
counter-increment: item;
content: counter(item) ". ";
}
#tocList>li>ol {
counter-reset: item2;
}
#tocList>li>ol>li:before {
counter-increment: item2;
content: counter(item) "." counter(item2) " ";
}
#tocList>li>ol>li>ol {
counter-reset: item3;
}
#tocList>li>ol>li>ol>li:before {
counter-increment: item3;
content: counter(item) "." counter(item2) "." counter(item3) " ";
}
#tocList>li>ol>li>ol>li>ol {
counter-reset: item4;
}
#tocList>li>ol>li>ol>li>ol>li:before {
counter-increment: item4;
content: counter(item) "." counter(item2) "." counter(item3) "."
counter(item4) " ";
}
#tocList>li>ol>li>ol>li>ol>li>ol {
counter-reset: item5;
}
#tocList>li>ol>li>ol>li>ol>li>ol>li:before {
counter-increment: item5;
content: counter(item) "." counter(item2) "." counter(item3) "."
counter(item4) "." counter(item5) " ";
}
Mã CSS hiệu ứng cuộn mượt đồng thời làm cho heading cách phần trên 100px để không bị che khuất bởi phần Header.
html {
scroll-behavior: smooth;
}
:target {
scroll-margin-top: 100px;
}
Bài Viết Liên Quan