1

I use Parsedown for transforming my Markdown into HTML like:

$pd->text('# My First heading');

In want automatically use the first site heading (h1) as an entry for a custom menu. I already had a look into the source, but couldn't figure out a good way to get all headings.

Perhaps there is something in elements function. Does anyone has an idea to get all or at least the first heading.

Emanuil Rusev
  • 34,563
  • 55
  • 137
  • 201
Tobias Redmann
  • 164
  • 1
  • 11

2 Answers2

5

@tobias-redmann

couldn't figure out a good way to get all headings

I assume you already solved this problem. But since I had the same problem and came up with the answer, I would like to share some info for those who will confront with the same problem.

TL;DR

Getting ToC (Table of Contents) w/ Parsedown.

<?php

include('Parsedown.php');

class Extension extends Parsedown
{
    public $array_line = array();

    // Override
    protected function blockHeader($Line)
    {
        // Parse $Line to parent class
        $Block = Parsedown::blockHeader($Line);

        // Set headings
        if(isset($Block['element']['name'])){
            $Level = (integer) trim($Block['element']['name'],'h');
            $this->array_line[] = [
                'text'  => $Block['element']['name'],
                'level' => $Level,
            ];
        }

        return $Block;
    }
}

$text = file_get_contents('YourMarkdownFile.md');

$Parsedown   = new Extension();
$string_body = $Parsedown->text($text);
$array_ToC   = $Parsedown->array_line;

print_r($array_ToC);
//echo $string_body;

TS;DR (Details)

First of all, as @emanuil-rusev said, overriding the blockHeader method, you can get all the headings from the markdown text.

More specifically, when you call text($text) method, it parses the markdown strings given.

While parsing, the blockHeader($Line) method will be called every line with an array argument such as below.

$Line => [
    "body"   => "# SampleHead",
    "indent" => 0,
    "text"   => "# SampleHead",
]

The original (parent) class' blockHeader($Line) method converts $Line into the following array($Block).

$Block => [
    "element" => [
        "name"    => "h1",
        "text"    => "# SampleHead",
        "handler" => "line",
    ],
]

So, the easiest way to get all the headings is to store these each time into an array.

Full script (extension) to get table of contents

See my repo: https://github.com/KEINOS/parsedown-extension_table-of-contents

KEINOS
  • 1,050
  • 2
  • 13
  • 32
4

Author of Parsedown here.

You should be able to achieve this by creating an extension that overrides the blockHeader method. Basically, the overriding method should modify the result of the parent method.

Have a look at the Parsedown wiki for more info.

Abhi Beckert
  • 32,787
  • 12
  • 83
  • 110
Emanuil Rusev
  • 34,563
  • 55
  • 137
  • 201