keinos/parsedown-toc

Table of Contents Extension for Parsedown, the Parser for Markdown.

v1.4.1 2025-05-07 03:19 UTC

This package is auto-updated.

Last update: 2025-05-09 02:33:06 UTC


README

Unit Tests Supported PHP Version Badge Parsedown Version Badge PHPDoc Badge

Parsedown ToC Extension

Listing Table of Contents Extension for Parsedown.

This simple PHP file extends Parsedown Vanilla / Parsedown Extra to generate a list of header index (a.k.a. Table of Contents or ToC), from a markdown text given.

Basic Usage

<?php

// Include the Parsedown and the ToC extension
require_once('Parsedown.php');
require_once('Extension.php');

// Markdown Data Sample
$inputMarkdown = <<<EOL
# Head1
Sample text of head 1.
## Head1-1
Sample text of head 1-1.
# Head2
Sample text of head 2.
## 見出し2-1
Sample text of head2-1.
EOL;

// Instanciate the Parsedown with ToC extension
$parser = new \ParsedownToc();

// Get the parsed HTML
$html = $parser->text($inputMarkdown);

// Get the Table of Contents in HTML
$tocHTML = $parser->contentsList('html');

// Print the parsed HTML and ToC
echo $html . PHP_EOL;
echo "---" . PHP_EOL;
echo $tocHTML . PHP_EOL;
$ php ./index.php
<h1 id="Head1" name="Head1">Head1</h1>
<p>Sample text of head 1.</p>
<h2 id="Head1-1" name="Head1-1">Head1-1</h2>
<p>Sample text of head 1-1.</p>
<h1 id="Head2" name="Head2">Head2</h1>
<p>Sample text of head 2.</p>
<h2 id="%E8%A6%8B%E5%87%BA%E3%81%972-1" name="%E8%A6%8B%E5%87%BA%E3%81%972-1">見出し2-1</h2>
<p>Sample text of head2-1.</p>
---
<ul>
<li><a href="#Head1">Head1</a>
<ul>
<li><a href="#Head1-1">Head1-1</a></li>
</ul></li>
<li><a href="#Head2">Head2</a>
<ul>
<li><a href="#%E8%A6%8B%E5%87%BA%E3%81%972-1">見出し2-1</a></li>
</ul></li>
</ul>
  • For more examples see the examples directory.

Installation

This extension, ParsedownToC, is a single PHP file. Download and place it in the same directory as the Parsedown.php file (optionally place the ParsedownExtra.php file if you are using it).

Manual Install

You can download the latest 'Extension.php' file from the below URL. Place it anywhere you like to include.

https://KEINOS.github.io/parsedown-extension_table-of-contents/Extension.php
# Download via cURL
curl -O https://KEINOS.github.io/parsedown-extension_table-of-contents/Extension.php
# Download via PHP
php -r "copy('https://KEINOS.github.io/parsedown-extension_table-of-contents/Extension.php', './Extension.php');"

Since this is an extension of Parsedown, you need to download and include Parsedown.php as well.

Via Composer

We also support Composer for installation and convenience.

# Current stable
composer require keinos/parsedown-toc

# Latest
composer require keinos/parsedown-toc:dev-master
Basic Usage Using Composer

To use the extension via Composer, include the autoloader (vendor/autoload.php file) instead of the Parsedown.php and Extension.php file.

$ cat ./parse_sample.php
<?php
require_once __DIR__ . '/vendor/autoload.php';

// Sample Markdown with '[toc]' tag included
$text_markdown = file_get_contents('SAMPLE.md');

$parser = new \ParsedownToC();

// Parse Markdown and the '[toc]' tag to HTML
$html = $parser->text($text_markdown);

echo $html . PHP_EOL;
$ cat ./SAMPLE.md
[toc]

---

# One
Something about One

## Two
Something about Two

# One2
Something about One2
$ php ./parse_sample.php
<div id="toc"><ul>
<li><a href="#One">One</a><ul>
<li><a href="#Two">Two</a></li>
</ul>
</li>
<li><a href="#One2">One2</a></li>
</ul></div>
<hr />
<h1 id="One" name="One">One</h1>
<p>Something about One</p>
<h2 id="Two" name="Two">Two</h2>
<p>Something about Two</p>
<h1 id="One2" name="One2">One2</h1>
<p>Something about One2</p>

Requirements

PardesownToC itself supports PHP 5.5 up-to current latest PHP 8.4.

However, the latest stable release of Parsedown 1.7.4 do not fully support PHP 8.4. And Parsedown Extra 0.8.1 do not fully support PHP 8.2 or later. Which throws deprecation warnings of PHP.

Stable Combination

To use the stable released version of Parsedown 1.7.4 and Parsedown Extra 0.8.1, you need to use between PHP 5.5 and PHP 8.1.

With later PHP versions you will get several deprecation warnings.

Script Name Versions
PHP Static Badge
Parsedown.php Parsedown Version Badge
SHA256 Hash: af4a4b29f38b5a00b003a3b7a752282274c969e42dee88e55a427b2b61a2f38f
ParsedownExtra.php ParsedownExtra Version Badge
SHA256 Hash: b0c6bd5280fc7dc1caab4f4409efcae9fb493823826f7999c27b859152494be7

Last-gasp Effort Combination

We have patched versions of Parsedown 1.7.4 and Parsedown Extra 0.8.1 to support PHP 8.4, the current latest PHP version.

These patched versions do not have any new features or refactoring made. Only the deprecation warnings from PHP are removed.

Use these combinations if you want to use the exact same features as the stable version with the latest PHP version.

Script Name Versions
PHP Static Badge
Parsedown.php (patched) Parsedown Version Badge
SHA256 Hash: b81a67cdd55e984bacc5fa5be84a15794de94b71841a18a9028a13ab9a41756a
(no new feature and refactoring)
ParsedownExtra.php (patched) ParsedownExtra Version Badge

Note

We are not supporting Parsedown v2 or above until the official beta release.

Class Info and Methods

For more details, please refer to the PHP Doc reference.

  • Main Class: ParsedownToC()
    • Arguments: none
    • Methods:
      • text(string $text):
        • Returns the parsed content and [toc] tag(s) parsed as well
        • Required argument:
          • $text: Markdown string to be parsed
      • body(string $text [, bool $omit_toc_tag=false]):
        • Returns the parsed content WITHOUT parsing [toc] tag
        • Required argument:
          • $text: Markdown string to be parsed
        • Optional argument:
          • $omit_toc_tag: If true, the [toc] tag will be excluded from the output
          • Default: false
          • Available since v1.3.0
      • contentsList([string $type_return='string']):
        • Returns the ToC, the table of contents, in HTML or JSON.
        • Optional argument:
          • $type_return: Specifies the returned format
            • "string" or "json" can be specified. string=HTML, json=JSON.
            • Default "string"
      • setTagToc(string $tag='[tag]'):
        • Sets user defined ToC markdown tag. Empty value sets the default tag
        • Default: "[toc]"
        • Available since v1.1.2
        • Note: Use this method before text() or body() method if you want to use the ToC tag rather than the "[toc]"
    • Other Methods:
      • All the public methods of Parsedown and/or Parsedown Extend are available to use
    • Note: As of ParsedownToC v1.1.0 the old alias class Extension() is deprecated

Online Demo

Advanced Usage (Using Parsedown Extra)

As of ParsedownToC v1.1.1, you can use the anchor identifiers for Parsedown Extra.

With this feature, you can specify the anchor name you like. Useful if the headings are in UTF-8 (not in ASCII) and to make it readable. Such as placing the "go back" links in a page.

# SampleHead1 {#self-defined-head1}
Sample text of head 1

---

[Link back to header 1](#self-defined-head1)

With the above markdown the generated ToC will be as below. Note that the anchor is changed to the specified one.

<ul>
<li><a href="#self-defined-head1">SampleHead1</a></li>
</ul>
  • Note that you need to require/include the Parsedown Extra as well.

Testing

Eventhough we are migraing the tests to PHPUnit, currently we use hand-made test scripts to run the unit tests via bash.

Testing using docker (docker compose)

# PHP 5.6.40 is not officially supported but used to check for backwards
# compatibility (still works tho!)
docker compose run --rm oldest

# PHP 7.x is the minimum supported version.
docker compose run --rm min

# PHP 8.3 is the stable supported version.
docker compose run --rm stable

# PHP 8.4+ (latest) is the experimental version. Currently uses the patched Parsedown 1.7.4.
docker compose run --rm latest

Testing locally

To run the tests:

./tests/run-tests.sh

Important

This test will download/install dependencies such as: Parsedown.php, ParsedownExtra.php, git, jq, curl and bash if not installed. So please run this test in a safe Unix-like environment (docker for example).

$ # Test result example (w/ oldest supported version)
$ ./tests/run-tests.sh
--------------------------------
Running tests in Alpine Linux OS
--------------------------------
================================
 Env checks before testing
================================
- Info: OS ...
  NAME="Alpine Linux"
  ID=alpine
  VERSION_ID=3.8.2
  PRETTY_NAME="Alpine Linux v3.8"
  HOME_URL="http://alpinelinux.org"
  BUG_REPORT_URL="http://bugs.alpinelinux.org"

- Checking: php ...
  php installed:   PHP 5.6.40 (cli) (built: Jan 31 2019 01:25:07)
  Copyright (c) 1997-2016 The PHP Group
  Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

- Checkging: apk ...
  apk installed: apk-tools 2.10.6, compiled for x86_64.
- Checking: jq ...
  jq installed: jq-master-v3.7.0-4757-gc31a4d0fd5
- Checking: curl ...
  curl installed: curl 7.61.1 (x86_64-alpine-linux-musl) libcurl/7.61.1 LibreSSL/2.0.0 zlib/1.2.11 libssh2/1.9.0 nghttp2/1.39.2
- Checking: bash ...
  bash installed: GNU bash, version 4.4.19(1)-release (x86_64-alpine-linux-musl)
- Lint Check: Extension.php ... OK
  No syntax errors detected in /app/Extension.php
- Searching Parsedown ... Found
- Searching Parsedown Extra ... Found
================================
 Running tests
================================
Parsedown Vanilla
- TESTING: test_vanilla_basic_usage.sh  ... OK (Parser: ./parser/parser-vanilla.php)
- TESTING: test_vanilla_empty_user_defined_toc_tag_style.sh  ... OK (Parser: ./parser/parser-vanilla.php)
- TESTING: test_vanilla_operation_check.sh  ... OK (Parser: ./parser/parser-vanilla.php)
- TESTING: test_vanilla_user_defined_toc_tag_style1.sh  ... OK (Parser: ./parser/parser-vanilla.php)
- TESTING: test_vanilla_user_defined_toc_tag_style2.sh  ... OK (Parser: ./parser/parser-vanilla.php)
- TESTING: test_vanilla_user_defined_toc_tag_style3.sh  ... OK (Parser: ./parser/parser-vanilla.php)

Parsedown Extra
- TESTING: test_vanilla_basic_usage.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_vanilla_empty_user_defined_toc_tag_style.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_vanilla_operation_check.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_vanilla_user_defined_toc_tag_style1.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_vanilla_user_defined_toc_tag_style2.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_vanilla_user_defined_toc_tag_style3.sh  ... OK (Parser: ./parser/parser-extra.php)
- TESTING: test_extra_anchor_id.sh  ... OK (Parser: ./parser/parser-extra.php)

Issues/Features
- TESTING: feature #22: option arg to exclude ToC tag in `body`
  - test #1: enable to omit the ToC tag in the body of the document ... OK
  - test #2: disable to omit the ToC tag in the body of the document (default) ... OK

Test done. All tests passed.

References