Skip to content

Tutorial: Create Extensions

Benjamin Høegh edited this page Aug 13, 2023 · 11 revisions

Contents


Disable Element

This example disables Header elements. That is, both Atx Header and Setext Header elements.

class Extension extends Parsedown
{

    protected function blockHeader($Line)
    {
        return;
    }

    protected function blockSetextHeader($Line, array $Block = null)
    {
        return;
    }

}

You can use the same approach for other elements types. This includes inline element types. For example, to disable Image elements you should override inlineImage.

Note that to disable all headers you should also disable support for HTML. You can do that by setting the MarkupEscaped option to true.

Change Element Markup

This example prepends a base path to the src of Image elements.

class Extension extends Parsedown
{

    private $baseImagePath = 'http://cdn.example.com/';

    protected function inlineImage($excerpt)
    {
        $image = parent::inlineImage($excerpt);

        if ( ! isset($image))
        {
            return null;
        }

        $image['element']['attributes']['src'] = $this->baseImagePath . $image['element']['attributes']['src'];

        return $image;
    }

}

You can use the same approach for other element types.

Add Inline Element

This example adds a ColoredText element. You can find a description of this element at https://github.com/erusev/parsedown/issues/262.

class Extension extends Parsedown
{

    function __construct()
    {
        $this->InlineTypes['{'][]= 'ColoredText';

        $this->inlineMarkerList .= '{';
    }

    protected function inlineColoredText($excerpt)
    {
        if (preg_match('/^{c:([#\w]\w+)}(.*?){\/c}/', $excerpt['text'], $matches))
        {
            return array(

                // How many characters to advance the Parsedown's
                // cursor after being done processing this tag.
                'extent' => strlen($matches[0]), 
                'element' => array(
                    'name' => 'span',
                    'text' => $matches[2],
                    'attributes' => array(
                        'style' => 'color: ' . $matches[1],
                    ),
                ),

            );
        }
    }

}

You can use the same approach for other element types.

Add Multi-Line Element

This example extends the bold element (**) to work on multiple lines.

class Extension extends Parsedown
{

    /**
     * The array index is the first character of the pattern to match.
     * It is not possible to define patterns longer than one character directly here, as only the first
     * character of the line will be checked. (eg. Setting $this->BlockTypes['{tag'] won't work.)
     *
     * The second array is a list of all functions that should be called when the character is found.
     *
     * Leave out the 'block' or 'inline' part of the function name, as it will be prepended automatically.
     */
    function __construct()
    {
        $this->BlockTypes['*'][] = 'BoldText'; 
    }

    protected function blockBoldText($line, $block)
    {
        if (preg_match('/^\*\*/', $line['text'], $matches))
        {
            return array(
                'char' => $line['text'][0],
                'element' => array(
                    'name' => 'strong',
                    'text' => '',
                ),
            );
        }
    } 

    /**
     * Appending the word `continue` to the function name will cause this function to be
     * called to process any following lines, until $block['complete'] is set to be 'true'.
     */
    protected function blockBoldTextContinue($line, $block)
    {
        if (isset($block['complete']))
        {
            return;
        }

        // A blank newline has occurred.
        if (isset($block['interrupted']))
        {
            $block['element']['text'] .= "\n";
            unset($block['interrupted']);
        }

        // Check for end of the block. 
        if (preg_match('/\*\*/', $line['text']))
        {
            $block['element']['text'] = substr($block['element']['text'], 1);

            // This will flag the block as 'complete':
            // 1. The 'continue' function will not be called again.
            // 2. The 'complete' function will be called instead.
            $block['complete'] = true;
            return $block;
        }
        
        $block['element']['text'] .= "\n" . $line['body'];
        
        return $block;
    }

    /**
     * Appending the word `complete` to the function name will cause this function to be
     * called when the block is marked as *complete* (see the previous method).
     */
    protected function blockBoldTextComplete($block)
    {
        return $block;
    }

}

Structure

$line

The $line structure represents a single line of text from the input Markdown content.

Key Components:

  • text: This is the actual content of the line being parsed.
  • indent: Represents the number of spaces at the start of the line. Useful for identifying block elements, like blockquotes or code blocks.
  • body: It's the content of the line with the leading whitespace (determined by indent) removed.

$block

The $block structure represents a block-level element in Markdown, such as paragraphs, lists, headers, blockquotes, and more.

Key Components:

  • type: Identifies the type of the block (e.g., 'Paragraph', 'Header', 'List', etc.).
  • indent: The base indentation level of the block.
  • handler: Specifies how the content of the block should be processed. It usually contains:
    • function: The method used to process the block's content.
    • argument: Arguments passed to the processing function. Typically, it's the content of the block.
    • destination: Determines where the output of the processing function should be stored.
  • element: Contains the final parsed content of the block, ready to be converted to HTML. It typically includes:
    • name: The name of the HTML element that represents this block.
    • text: The text content of the element.
    • elements: An array of sub-elements contained within this block.
    • attributes: Any attributes to be added to the HTML element.
  • pattern: (For lists) A regex pattern to match the list marker.
  • data: Additional data specific to the block type. For example, for lists, it can contain the marker type (*, -, or + for unordered lists and numbers for ordered lists).