Learn how to implement a table of contents in WordPress without using a plugin.
This method does not use JQuery and is also the implementation method introduced on this website.
It takes less time and man-hours, if you like.
The following steps are to be implemented.
- Edit functions.php.
- Editing CSS.
- Set display conditions on the Appearance → Customise screen.
- Adjustment of display and non-display within individual articles.
Edit functions.php.
If a child theme is available, use the child theme’s functions.php.
The instructions for each code are given at the top of each code for reference.
※Always make a backup before editing.
//////////////////////////////////////////////////
//Original sanitize_callback
//////////////////////////////////////////////////
// CheckBox
function fit_sanitize_checkbox( $checked ) {
return ( ( isset( $checked ) && true == $checked ) ? true : false );
}
// radio/select
function fit_sanitize_select( $input, $setting ) {
$input = sanitize_key( $input );
$choices = $setting->manager->get_control($setting->id)->choices;
return ( array_key_exists( $input, $choices ) ? $input : $setting->default );
}
// number limit
function fit_sanitize_number_range( $number, $setting ) {
$number = absint( $number );
$atts = $setting->manager->get_control( $setting->id )->input_attrs;
$min = ( isset( $atts['min'] ) ? $atts['min'] : $number );
$max = ( isset( $atts['max'] ) ? $atts['max'] : $number );
$step = ( isset( $atts['step'] ) ? $atts['step'] : 1 );
return ( $min <= $number && $number <= $max && is_int( $number / $step ) ? $number : $setting->default );
}
//////////////////////////////////////////////////
//Post page various setting screens
//////////////////////////////////////////////////
function fit_post_cutomizer( $wp_customize ) {
// Section
$wp_customize->add_section( 'fit_post_section', array(
'title' => 'Post page settings',
'priority' => 1,
));
// Show/hide table of contents Settings
$wp_customize->add_setting( 'fit_post_outline', array(
'default' => 'value1',
'type' => 'option',
'sanitize_callback' => 'fit_sanitize_select',
));
// Show/hide table of contents Controls
$wp_customize->add_control( 'fit_post_outline', array(
'section' => 'fit_post_section',
'settings' => 'fit_post_outline',
'label' => '■Show/hide table of contents',
'description' => 'Select whether to display a table of contents on the post page<br>
(It is automatically inserted before the first h-tag in the article.※
Can be displayed in any position with a shortcode.)',
'type' => 'select',
'choices' => array(
'value1' => 'Display(default)',
'value2' => 'Do not display',
),
));
// Minimum number of headings for displaying the table of contents Settings
$wp_customize->add_setting( 'fit_post_outline_number', array(
'default' => '1',
'type' => 'option',
'sanitize_callback' => 'fit_sanitize_number_range',
));
// Minimum number of headings for displaying the table of contents Control
$wp_customize->add_control( 'fit_post_outline_number', array(
'section' => 'fit_post_section',
'settings' => 'fit_post_outline_number',
'description' => 'Specify the minimum number of headings to display the table of contents.',
'type' => 'number',
'input_attrs' => array(
'step' => '1',
'min' => '1',
'max' => '50',
),
));
// Contents Panel default settings Settings
$wp_customize->add_setting('fit_post_outline_close', array(
'type' => 'option',
'sanitize_callback' => 'fit_sanitize_checkbox',
));
// Contents Panel default settings Controls
$wp_customize->add_control('fit_post_outline_close', array(
'section' => 'fit_post_section',
'settings' => 'fit_post_outline_close',
'label' => 'Keep the table of contents panel closed by default.',
'type' => 'checkbox',
));
}
add_action( 'customize_register', 'fit_post_cutomizer' );
//////////////////////////////////////////////////
//Show/hide table of contents, individual selection settings
//////////////////////////////////////////////////
if ( get_option('fit_post_outline') != 'value2') {
function add_outline_fields() {
//add_meta_box(ID of the HTML of the input box to be displayed, labels, function name to create the content to be displayed, post type, display method.)
add_meta_box( 'outline_setting', 'Individual hide settings for the table of contents.', 'insert_outline_fields', 'post', 'normal');
}
add_action('admin_menu', 'add_outline_fields');
// Input area for custom fields.
function insert_outline_fields() {
global $post;
if( get_post_meta($post->ID,'outline_none',true) == "1" ) {
$outline_none_check = "checked";
}else {
$outline_none_check = "";
}
echo '
<div style="margin:20px 0; overflow: hidden; line-height:2;">
<div style="float:left;width:120px;">Table of contents display settings.</div>
<div style="float:right;width:calc(100% - 140px);">
<input type="checkbox" name="outline_none" value="1" '.$outline_none_check.' >:Do you want to hide the table of contents in this post?
</div>
<div style="clear:both;"></div>
</div>
';
}
// Save custom field values.
function save_outline_fields( $post_id ) {
if(!empty($_POST['outline_none'])){
update_post_meta($post_id, 'outline_none', $_POST['outline_none'] );
}else{
delete_post_meta($post_id, 'outline_none');
}
}
add_action('save_post', 'save_outline_fields');
}
//////////////////////////////////////////////////
//Create original table of contents.
//////////////////////////////////////////////////
function get_outline_info($content) {
// Define a variable to contain the HTML of the table of contents.
$outline = '';
// h1?h6Define a variable to contain the number of tags.
$counter = 0;
// Search for h1?h6 tags in articles.(Improved to also include id and class attributes).
if (preg_match_all('/<h([1-4])[^>]*>(.*?)<\/h\1>/', $content, $matches, PREG_SET_ORDER)) {
// Get the smallest number in the h1?h6 tags used in the article, h1?h6.
// ※The word level in the source since then stands for h1?h6.
$min_level = min(array_map(function($m) { return $m[1]; }, $matches));
// Determines the starting level.
// ※Each time this level is increased, more <ul></li> tags are added.
$current_level = $min_level - 1;
// Define an array to store the number of occurrences of each level.
$sub_levels = array('1' => 0, '2' => 0, '3' => 0, '4' => 0);
// Loop over the number of h-tags, found in the article.
foreach ($matches as $m) {
$level = $m[1]; // Get the level of the h-tag found.
$text = $m[2]; // Get the content of the tag, of the h-tag found.
// This is the process of closing the li, ul tags, which may go inside after the second loop.
// For example, if the last time it was processed was for an h3 tag and the one that appeared this time was for an h2 tag,
// Close the ul for the h3 tag and prepare for the h2 tag.
while ($current_level > $level) {
$current_level--;
$outline .= '</li></ul>';
}
// For the same LEVEL, close the LI tag and open a new one.
if ($current_level == $level) {
$outline .= '</li><li class="outline__item">';
} else {
// If not on the same level, add ul and li tags.
// For example, if the last time it was processed was for an h2 tag and the one that appeared this time was for an h3 tag,
// Add ul for h3 tags.
while ($current_level < $level) {
$current_level++;
$outline .= sprintf('<ul class="outline__list outline__list-%s"><li class="outline__item">', $current_level);
}
// If the level of the heading changes, the number of occurrences below the current level is reset.
for ($idx = $current_level + 0; $idx < count($sub_levels); $idx++) {
$sub_levels[$idx] = 0;
}
}
// Update the array storing the number of occurrences at each level.
$sub_levels[$current_level]++;
// Defines an array containing the path of the h-tag currently being processed.
// For example, if you are proceeding with h2 -> h3 -> h3 tags,
// level_fullpath is like array(1, 2).
// ※The 1 in level_fullpath[0] indicates that it is directly under the first h2 tag.
// ※The 2 in level_fullpath[1] represents the second h3.
$level_fullpath = array();
for ($idx = $min_level; $idx <= $level; $idx++) {
$level_fullpath[] = $sub_levels[$idx];
}
$target_anchor = 'outline__' . implode('_', $level_fullpath);
// Add headings to the table of contents in the form of <a href="#outline_1_2">1.2 Headings</a>.
$outline .= sprintf('<a class="outline__link" href="#%s"><span class="outline__number" style="display:none;">%s.</span> %s</a>', $target_anchor, implode('.', $level_fullpath), strip_tags($text));
// Heading body in the text, <h3> heading</h3> to <h3id="outline_1_2">Headline</h3>
// Replace it with a form such as.
$hid = preg_replace('/<h([1-6])/', '<h\1 id="' .$target_anchor . '"', $m[0]);
$content = str_replace($m[0], $hid, $content);
}
// After the loop of the h tag ends, the unclosed ul tag is closed.
while ($current_level >= $min_level) {
$outline .= '</li></ul>';
$current_level--;
}
// Number of h1?h6 tags
$counter = count($matches);
}
return array('content' => $content, 'outline' => $outline, 'count' => $counter);
}
//Create a table of contents.
function add_outline($content) {
// Number of headings required to display the table of contents.
if(get_option('fit_post_outline_number')){
$number = get_option('fit_post_outline_number');
}else{
$number = 1;
}
// Retrieve information related to the table of contents.
$outline_info = get_outline_info($content);
$content = $outline_info['content'];
$outline = $outline_info['outline'];
$count = $outline_info['count'];
if (get_option('fit_post_outline_close') ) {
$close = "";
}else{
$close = "checked";
}
if ($outline != '' && $count >= $number) {
// Decorate the table of contents.
$decorated_outline = sprintf('
<div class="outline">
<span class="outline__title">目次</span>
<input class="outline__toggle" id="outline__toggle" type="checkbox" '.$close.'>
<label class="outline__switch" for="outline__toggle"></label>
%s
</div>', $outline);
// Add a table of contents when other than Hide table of contents is selected in the customiser & when the individual hide is other than 1.
if ( get_option('fit_post_outline') != 'value2' && get_post_meta(get_the_ID(), 'outline_none', true) != '1' && is_single() ) {
$shortcode_outline = '
';
if (strpos($content, $shortcode_outline) !== false) {
// If there is a shortcode in the article, the shortcode is replaced by a table of contents.
$content = str_replace($shortcode_outline, $decorated_outline, $content);
} else if (preg_match('/<h[1-6].*>/', $content, $matches, PREG_OFFSET_CAPTURE)) {
// Add a table of contents before the first h-tag.
$pos = $matches[0][1];
$content = substr($content, 0, $pos) . $decorated_outline . substr($content, $pos);
}
}
}
return $content;
}
add_filter('the_content', 'add_outline');
function override_mce_options( $init_array ) {
global $allowedposttags;
$init_array['valid_elements'] = '*[*]';
$init_array['extended_valid_elements'] = '*[*]';
$init_array['valid_children'] = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']';
$init_array['indent'] = true;
$init_array['wpautop'] = false;
return $init_array;
}
add_filter( 'tiny_mce_before_init', 'override_mce_options' );
Editing CSS code.
CSS adjustments.
The CSS code is shown below.
Copy and paste the whole thing into any style sheet, such as style.css.
/*Table of Contents*/
.outline{
border:1px dotted #D8D8D8;
padding:20px;
margin-top:20px;
display:inline-block;
font-size:0.9em;
line-height:1.5em;
}
.outline__toggle{display: none;}
.outline__switch::before{
content:"Open";
cursor:pointer;
border: solid 1px #D8D8D8;
padding:5px;
font-size:0.8rem;
margin-left:5px;
border-radius: 5px;
}
.outline__toggle:checked + .outline__switch::before{content:"Close"}
.outline__switch + .outline__list{
overflow:hidden;
width:0;
height:0;
margin-top:0;
margin-left:-20px;
transition: 0.2s;
}
.outline__toggle:checked + .outline__switch + .outline__list {
width: auto;
height: auto;
margin-top: 20px;
transition: 0.2s;
border-top: dotted 1px #d2d2d2;
padding-top: 1em;
}
.outline__item:before {content: normal;}
.outline__link{
display:relative;
color:#191919 !important;
}
.outline__link:hover{border:none;}
.outline__number{
display: inline-block;
color:#7F7F7F;
background:#F2F2F2;
padding:3px 6px;
font-weight:400;
font-size:1.2rem;
margin-right: 5px;
}
label.outline__switch {
position: relative;
float: right;
}
li .outline__item{
list-style-type:none!important;
}
li .outline__item:before{
content:'- ';
}
ul .outline__item{
list-style-type:none!important;
}
ul{
-webkit-padding-start: 1.2em;
}
The design can be changed to any desired design by customising the CSS.
When you have finished editing the CSS, save it to the CSS used by your theme.
This completes the set-up.
Set display conditions on the Appearance → Customise screen.
Go to Appearance, Customise, Post Page Settings.
Select whether to display a table of contents on the post page.
The standard table of contents is displayed or not.
This item should basically be “Display”.
If you only need the table of contents occasionally, then “Hide” is fine.
Set the minimum number of headings to display the table of contents.
The table of contents is displayed if there are a number of headings.
A standard number is between 3 and 5.If you set it to 3, a table of contents will not be generated if there are only one or two headings.
This site is set at 2.
Keep the table of contents panel closed by default.
The table of contents field should be closed by default from the beginning.
This item should be left unchecked.
Adjustment of display and non-display within individual articles.
Basically, there is very little to manipulate, but there are times when you want to hide the table of contents due to the design and look and feel within a post, although the table of contents is displayed as standard with many headings.
In such cases, there is a check box in the individual article to check.
Conclusion.
In this article, we showed you how to implement a table of contents in WordPress without using a plugin.
The work itself does not take long and can be implemented quickly, so please refer to this if you like.
Thank you for watching until the end.
Code Web Without Plugin
The one you write in wp-config.php for now.
define( 'WP_DEBUG', false ); ini_set('display_errors','Off'); define('ALLOW_UNFILTERED_UPLOADS', true); define('WP_MEMORY_LIMIT', '100000000000000000000M'); define( 'WPMS_ON', true );
Continue readingCode Speed Web Wordpress
Without plugins!Contact Form 7 How to load js and css only on specified pages.|WordPress
Learn how to make ContactForm7 js and css load only on specified pages in WordPress without using a plugin. Normally, when ContactForm7 is installed, js and css are loaded on every page, which slows down the display speed, but this...
Continue readingCode Web Without Plugin Wordpress
Without Plugin!Easy copy and paste. how to add a site name shortcode to WordPress.
It is very time-consuming to rewrite site names when producing multiple sites. As a way of preventing this from happening, it is recommended to set up a system to call the name of the site by a shortcode. Write the...
Continue readingPlant
Obregonia denegrii.
One genus and one species of cactus, so majestic and dignified is its appearance that it is known as the ‘TEIKAN’. This is a very rare cactus and one of the most popular cacti, partly because of its beautiful rosette...
Continue readingCDN Security Speed
DNS configuration with Cloudflare.Set up bombastic DNS for a more comfortable IT life.
DNS configuration with Cloudflare not only speeds up browser start-up, but also contributes to improved security. Please give it a try. 1. 1.1.1.12. 1.1.1.1 family oriented.2.1. Blocks malware.2.2. Blocks malware and adult content. 1.1.1.1 1.1.1.1 is Cloudflare’s public DNS resolver.It...
Continue readingCDN Security Speed Web
Does CDN delivery with Cloudflare reduce AdSense revenue?Various setting methods.
1. The impact of Adsense.2. The cause is that individual IPs are indistinguishable through Cloudflare (they are all the same IP through Cloudflare).3. How to make Nginx recognise individual IPs differentially.4. How to make apache recognise individual IPs separately. The...
Continue readingCode Web Without Plugin Youtube
How to make YouTube embedding responsive while maintaining proportions with CSS.
Learn how to make YouTube embeds responsive while maintaining the ratio. 1. 1:Add div tag.2. 2:Add css.3. Finalise. 1:Add div tag. Add a div tag to enclose the iframe tag. <div class="yt"><iframe width="560" height="315" src="https://www.youtube.com/embed/YUDbl9qBihk?si=RRyI62O5tVSEfHvo" title="YouTube video player" frameborder="0" allow="accelerometer;...
Continue readingSponsor
Frecer Sponsorship applications are now open!
We are pleased to announce that we are now accepting applications for Frecer sponsorship. Sponsor We offer a variety of plans and special offers. The funds you support will help to realise a number of projects. We sincerely look forward...
Continue readingPlant
What is a cactus. Origin and characteristics of ‘Cactos’ [1].
The word ‘Cactus’ derives from the Greek word ‘Kàktos’. The term was used by Theophrastus in his book HistoriaPlantarum to describe ‘unknown thorny plants’. The term ‘Cactus’ was subsequently adopted by the renowned botanist Linneo to define the American thorny...
Continue readingCode Security Web Wordpress
How to make all pages permanently SSL.WordPress
Has SSL been installed on your website? The introduction of SSL is recommended for all websites because of its security and SEO advantages. Full-page SSL is particularly desirable for shopping and crowdfunding websites where personal data and payments are involved....
Continue reading