{"id":630,"date":"2023-05-12T21:00:43","date_gmt":"2023-05-12T14:00:43","guid":{"rendered":"https:\/\/dev.artru.eu.org\/?p=630"},"modified":"2023-08-21T17:36:52","modified_gmt":"2023-08-21T10:36:52","slug":"tao-muc-luc","status":"publish","type":"post","link":"https:\/\/artru.net\/en\/tao-muc-luc\/","title":{"rendered":"Create a table of contents in Oxygen Builder"},"content":{"rendered":"<h2 class=\"wp-block-heading\">Why don&#039;t I use a table of contents plugin?<\/h2>\n\n\n\n<p>For &quot;low tech&quot; brothers, just hit the TOC plugin for fast, neat and quick. I myself like to play around because this &quot;table of contents&quot; is not a big deal, but for it to work well, it also needs to be configured properly.<\/p>\n\n\n\n<p>I used to use Gutenberg&#039;s TOC. Everything was great until I decided to change to another plugin. I have to delete the block that creates the table of contents for each article, Oh! Oh my God. Luckily, I only had about 10 posts back then.<\/p>\n\n\n\n<p>From that day on, I decided to change which plugin has the function of automatically creating a table of contents according to the heading tag title. Too bad there is nothing that makes the picture happy, if it&#039;s genuine, you have to pay a fee.<\/p>\n\n\n\n<p>Thanks to AI technology like ChatGPT, Bard, Bing, I can create &quot;home-made TOC&quot;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to create a table of contents correctly?<\/h2>\n\n\n\n<p>Before creating a TOC, we need to understand how to configure the table of contents to be SEO-friendly and user-friendly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Friendly Anchor Link<\/h3>\n\n\n\n<p>There are plugins that create a table of contents automatically but set heading tags as <code data-no-translation=\"\" data-no-auto-translation=\"\">id=\"section-1\"<\/code> and the link pointing to this heading tag is <code data-no-translation=\"\" data-no-auto-translation=\"\">href=\"#section-1\"<\/code>.<\/p>\n\n\n\n<p>So you need to pay attention to these little details. Currently there may not be much demand for this issue.<\/p>\n\n\n\n<p>Here are a few standard link anchor examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/en\/tao-muc-luc\/#anchor-link-than-thien\" target=\"_blank\" rel=\"noreferrer noopener\">Test this link in ARTRU&#039;s site<\/a>.<\/li>\n\n\n\n<li><a href=\"https:\/\/wpcanban.com\/wordpress\/thu-thuat-wordpress\/tinh-gian-plugin-litespeed-cache.html#an-cac-menu-khong-dung\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">This link points to WPcanban&#039;s &quot;# Hide unused menus&quot;<\/a>.<\/li>\n\n\n\n<li><a href=\"https:\/\/rankmath.com\/kb\/table-of-contents-block\/#num-4-1-table-of-contents-title\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">This link points to &quot;# Table of Contents Title&quot; by Rank Math<\/a>.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Smooth Scroll (Smooth Scroll)<\/h3>\n\n\n\n<p>Help users feel more comfortable, more eye-catching.<\/p>\n\n\n\n<p>It is especially useful to use a url with a #hashtag sent from another site to help users know where this #hashtag item is located in the article.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sticky (Pin) table of contents<\/h3>\n\n\n\n<p>This is also a good feature for users. When reading the article they can know where they are reading the article instead of having to scroll to the top of the page to check the table of contents.<\/p>\n\n\n\n<p>Currently, I have not used this feature for the website. Will update if there are any changes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Instructions for creating a table of contents<\/h2>\n\n\n\n<p>These codes I apply to the Oxygen Builder drag and drop. You can also apply to other Builders and Themes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code to create table of contents automatically<\/h3>\n\n\n\n<p>The code below has the function:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create cards <code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;a&gt;<\/code> according to h2-h6 in the article content.<\/li>\n\n\n\n<li>Add attributes <code data-no-translation=\"\" data-no-auto-translation=\"\">href=\"#\"<\/code> to the cards <code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;a&gt;<\/code>.<\/li>\n\n\n\n<li>Sort the cards <code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;a&gt;<\/code> according to the rule of recursion <code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;ol&gt; &lt;li&gt;<\/code><\/li>\n<\/ul>\n\n\n\n<p>Put <strong>PHP Code<\/strong> This places the position where you want the table of contents to be displayed.<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">\/* M\u00c3 PHP T\u1ea0O M\u1ee4C L\u1ee4C T\u1ef0 \u0110\u1ed8NG H2-H6. S\u1eec D\u1ee4NG get_the_content() *\/\nfunction generate_toc($content)\n{\n\tpreg_match_all('\/&lt;h(&#91;2-6]).*?&gt;(.*?)&lt;\\\/h\\1&gt;\/', $content, $matches, PREG_SET_ORDER);\n\t$toc           = '&lt;ol id=\"tocList\"&gt;';\n\t$current_level = 2;\n\tforeach ($matches as $match)\n\t{\n\t\t$level         = $match&#91;1];\n\t\t$heading       = $match&#91;2];\n\t\t$id            = sanitize_title($heading);\n\t\tif ($level &gt; $current_level)\n\t\t{\n\t\t\t$toc .= str_repeat('&lt;ol&gt;', $level - $current_level) . '&lt;li&gt;&lt;a href=\"#' . $id . '\"&gt;' . $heading . '&lt;\/a&gt;';\n\t\t}\n\t\telse if ($level &lt; $current_level)\n\t\t{\n\t\t\t$toc .= str_repeat('&lt;\/li&gt;&lt;\/ol&gt;', $current_level - $level) . '&lt;\/li&gt;&lt;li&gt;&lt;a href=\"#' . $id . '\"&gt;' . $heading . '&lt;\/a&gt;';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$toc .= '&lt;\/li&gt;&lt;li&gt;&lt;a href=\"#' . $id . '\"&gt;' . $heading . '&lt;\/a&gt;';\n\t\t}\n\t\t$current_level = $level;\n\t}\n\t$toc .= str_repeat('&lt;\/li&gt;&lt;\/ol&gt;', $current_level - 2);\n\t$content = '&lt;div id=\"tocDiv\"&gt;&lt;p&gt;M\u1ee4C L\u1ee4C&lt;\/p&gt;' . $toc . '&lt;\/div&gt;';\n\treturn $content;\n};\n$content          = get_the_content();\n$content_with_toc = generate_toc($content);\necho $content_with_toc;<\/code><\/pre>\n\n\n\n<p>After applying the above code, the table of contents will have the following structure:<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">&lt;div id=\"tocDiv\"&gt;\n\t&lt;p&gt;M\u1ee4C L\u1ee4C&lt;\/p&gt;\n\t&lt;ol id=\"tocList\"&gt;\n\t\t&lt;!-- Danh s\u00e1ch m\u1ee5c l\u1ee5c --&gt;\n\t\t&lt;li&gt;&lt;\/li&gt;\n\t\t&lt;li&gt;&lt;\/li&gt;\n\t\t&lt;li&gt;&lt;\/li&gt;\n\t&lt;\/ol&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Add &quot;id&quot; attribute to heading tags<\/h3>\n\n\n\n<p>This is for the purpose that when the user clicks on the link in the table of contents, they will move to the correct heading tag.<\/p>\n\n\n\n<p><strong>PHP Code<\/strong> to add the id for the heading tags that should be put in the file <code data-no-translation=\"\" data-no-auto-translation=\"\">function.php<\/code> in child theme or create more <code data-no-translation=\"\" data-no-auto-translation=\"\">mu-plugins<\/code> or maybe the same place where you put the code to create the table of contents above, but I don&#039;t recommend this way. <\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">\/* M\u00c3 PHP T\u1ea0O THU\u1ed8C T\u00cdNH ID CHO C\u00c1C TH\u1eba HEADING H2-H6 TRONG N\u1ed8I DUNG B\u00c0I VI\u1ebeT *\/\nfunction prefix_heading_ids($content)\n{\n\t$pattern = '#(?P&lt;full_tag&gt;&lt;(?P&lt;tag_name&gt;h\\d)(?P&lt;tag_extra&gt;&#91;^&gt;]*)&gt;(?P&lt;tag_contents&gt;&#91;^&lt;]*)&lt;\/h\\d&gt;)#i';\n\tif (preg_match_all($pattern, $content, $matches, PREG_SET_ORDER))\n\t{\n\t\t$find    = array();\n\t\t$replace = array();\n\t\tforeach ($matches as $match)\n\t\t{\n\t\t\tif (strlen($match&#91;'tag_extra']) &amp;&amp; false !== stripos($match&#91;'tag_extra'], 'id='))\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$find&#91;]         = $match&#91;'full_tag'];\n\t\t\t$id      = sanitize_title($match&#91;'tag_contents']);\n\t\t\t$id_attr = sprintf(' id=\"%s\"', $id);\n\t\t\t$replace&#91;]         = sprintf('&lt;%1$s%2$s%3$s&gt;%4$s&lt;\/%1$s&gt;', $match&#91;'tag_name'], $match&#91;'tag_extra'], $id_attr, $match&#91;'tag_contents']);\n\t\t}\n\t\t$content = str_replace($find, $replace, $content);\n\t}\n\treturn $content;\n}\nadd_filter('the_content', 'prefix_heading_ids');<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Recursively sort CSS code for table of contents<\/h3>\n\n\n\n<p>Below is the recursively sort CSS code for the wrapped table of contents &lt;div&gt; have id=&amp;quot;tocDiv&amp;quot; and &lt;ol&gt; has id=&amp;quot;tocList&amp;quot;.<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">#tocDiv {\n\twidth: 100%;\n\tborder-radius: 10px;\n\tbox-shadow: 5px 5px 10px 5px rgba(0, 0, 0, 0.5);\n\toverflow: hidden;\n\tmargin: 50px 0px 50px 0px;\n}\n#tocDiv p {\n\tfont-weight: bold;\n\ttext-align: center;\n\tdisplay: block;\n}\n#tocDiv ol {\n\tlist-style: none;\n}\n#tocList {\n\tpadding-left: 20px;\n\twhite-space: nowrap;\n\toverflow-x: auto;\n\tpadding-bottom: 20px;\n\tmargin-bottom: 0px;\n}\n#tocList a {\n\tmargin-right: 10px;\n}\n#tocList ol {\n\tpadding-left: 20px;\n}\n#tocList {\n\tcounter-reset: item;\n}\n#tocList&gt;li:before {\n\tcounter-increment: item;\n\tcontent: counter(item) \". \";\n}\n#tocList&gt;li&gt;ol {\n\tcounter-reset: item2;\n}\n#tocList&gt;li&gt;ol&gt;li:before {\n\tcounter-increment: item2;\n\tcontent: counter(item) \".\" counter(item2) \" \";\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol {\n\tcounter-reset: item3;\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol&gt;li:before {\n\tcounter-increment: item3;\n\tcontent: counter(item) \".\" counter(item2) \".\" counter(item3) \" \";\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol {\n\tcounter-reset: item4;\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol&gt;li:before {\n\tcounter-increment: item4;\n\tcontent: counter(item) \".\" counter(item2) \".\" counter(item3) \".\"\n\t\tcounter(item4) \" \";\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol {\n\tcounter-reset: item5;\n}\n#tocList&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol&gt;li&gt;ol&gt;li:before {\n\tcounter-increment: item5;\n\tcontent: counter(item) \".\" counter(item2) \".\" counter(item3) \".\"\n\t\tcounter(item4) \".\" counter(item5) \" \";\n}<\/code><\/pre>\n\n\n\n<p><strong>CSS Code<\/strong> smooth scrolling effect while making the heading 100px from the top so it&#039;s not obscured by the Header.<\/p>\n\n\n\n<pre class=\"wp-block-code\" data-no-translation=\"\" data-no-auto-translation=\"\"><code data-no-translation=\"\" data-no-auto-translation=\"\">html {\n\tscroll-behavior: smooth;\n}\n:target {\n\tscroll-margin-top: 100px;\n}<\/code><\/pre>","protected":false},"excerpt":{"rendered":"<p>T\u1ea1i sao t\u00f4i l\u1ea1i kh\u00f4ng d\u00f9ng plugin t\u1ea1o m\u1ee5c l\u1ee5c? \u0110\u1ed1i v\u1edbi anh em \"low tech\" c\u1ee9 phang plugin TOC cho nhanh, g\u1ecdn, l\u1eb9. B\u1ea3n th\u00e2n m\u00ecnh th\u00ec l\u1ea1i th\u00edch [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-630","post","type-post","status-publish","format-standard","hentry","category-oxygen-builder"],"_links":{"self":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts\/630","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/comments?post=630"}],"version-history":[{"count":0,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/posts\/630\/revisions"}],"wp:attachment":[{"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/media?parent=630"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/categories?post=630"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/artru.net\/en\/wp-json\/wp\/v2\/tags?post=630"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}