WordPress, KaTeX and the Showdown



We decided to use the javascript markdown engine [showdown](https://github.com/showdownjs/showdown) for the blawg, and [$\KaTeX$](https://khan.github.io/KaTeX/) for rendering latex. If you think that's a good way to go: ## Why we need some homebrew Alright, so what we wanted to do is write markdown in the WordPress backend interface, but $\alpha^*_k$ should be rendered as $\alpha^*_k$. Now there are plenty of showdown extensions like [this one](https://github.com/obedm503/katex-latex), but that is terribly uncomfortable. We wanted dollar symbols for inline latex. This is, in principle, solved by the [katex autorender extension](https://github.com/Khan/KaTeX/tree/master/contrib/auto-render), but the problem here is that when you have a markdown code block like $, $\KaTeX$ will completely destroy it. Another subtle problem is the following: If we have a markdown code block that contains unescaped HTML, then we can not output this to the website and have showdown parse it, because the unescaped HTML will screw up the DOM. Luckily, there is a solution to both problems. ## How to get those libraries quick & dirty At the time of writing:
$ wget https://github.com/Khan/KaTeX/releases/download/v0.7.1/katex.zip && unzip katex.zip && rm katex.zip
$ wget https://cdn.rawgit.com/showdownjs/showdown/1.7.1/dist/showdown.min.js
$ wget https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/contrib/auto-render.min.js
## WordPress Integration In your functions.php, we must first exterminate all wordpress filters for content and comments, then we load the js libraries in the right order. Finally, before passing the wordpress post (or comment) to the website, we just do one bit of markdown on the server side: The code blocks. This kills two birds with one stone, we can escape everything inside the code block before it reaches the browser and we can prevent $\KaTeX$ from interfering with markdown code blocks by turning them into *actual* HTML code blocks before $\KaTeX$ even sees them. I should mention that we use [github style code blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks/).
remove_all_filters('the_content');
remove_all_filters('comment_text');

function load_parsers() {
    wp_enqueue_style('parent-style', get_template_directory_uri().'/style.css');
    wp_enqueue_style('katex-style',  get_stylesheet_directory_uri().'/katex/katex.min.css');

    wp_enqueue_script('showdown',    get_stylesheet_directory_uri().'/showdown.min.js');
    wp_enqueue_script('katex-main',  get_stylesheet_directory_uri().'/katex/katex.min.js', array(), false, true);
    wp_enqueue_script('katex-auto',  get_stylesheet_directory_uri().'/auto-render.min.js', array('katex-main'), false, true);
    wp_enqueue_script('configure',   get_stylesheet_directory_uri().'/default.js', array('jquery', 'showdown', 'katex-auto'), false, true);
}
add_action('wp_enqueue_scripts', 'load_parsers');

function showdown_helper($content) {
  $blocks = preg_split('/$(\s*)(```)(\w*)\s*[\r\n]+(.*?)$\s*\2\s*$/sm',
      $content, NULL, PREG_SPLIT_DELIM_CAPTURE);
  $html = "";
  $step = 0;
  foreach ($blocks as $block) {
   switch ($step) {
   case 1:
    if ($block) $html .=  ' class="' . $block . '"';
    $html .= '>';
    $step = 2;
    break;
   case 2:
    $html .= htmlentities($block);
    $html .= '</code></pre>';
    $step = 0;
    break;
   default:
    if ($block==='```') {
     $step = 1;
     $html .= '<pre><code';
    } else {
     $html .=
       preg_replace_callback('/(`(?:`*))\s*(.*?)\s*\1/', 
        function($m){ return '<code>' . htmlentities($m[2]) . '</code>'; },
        $block);
    }
   }
  }
  return "<div class='showdown'>" . $html  . "\n</div>";
}


add_filter( 'the_content',  'showdown_helper' );
add_filter( 'comment_text', 'showdown_helper' );
## Activating the Libraries The following are the contents of default.js, which uses the libraries to perform the actual parsing. For every element with class .showdown, we first render $\KaTeX$ and then markdown. We implemented a tiny language extension for showdown here which unescapes the input, because we did escaping on the server side already.
jQuery(document).ready(function() {
    var $ = jQuery;
    var converter = new showdown.Converter({
        extensions: ['unquote']
    });
    converter.setFlavor('github');
    $('.showdown').map(function (i, elem) {
        var $elem = $(elem);
        renderMathInElement(elem,
         { delimiters: [
            {left:   "$", right:   "$", display: false},
            {left: "\\[", right: "\\]", display:  true}
           ],
           ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"],
         } );
        $elem.html( converter.makeHtml($.trim($elem.html())) );
    });
});

showdown.extension('unquote', function() {
  return [
    { type: 'lang', regex:  /&gt;/g, replace: '>' },
    { type: 'lang', regex:  /&lt;/g, replace: '<' },
    { type: 'lang', regex: /&amp;/g, replace: '&' },
  ]
});
## Bonus This is all completely compatible with the [WP Code Highlight.js](https://wordpress.org/plugins/wp-code-highlightjs/) plugin[1] to have syntax highlighting in our code blocks. Neat, huh? Just install the plugin on top of everything and it just works.
  1. if you also want it to be compatible with the [WP-Footnotes](https://elvery.net/drzax/wordpress-footnotes-plugin) plugin, you have to do some work. Drop me a line if you are fighting with this. [back]

One Reply to “WordPress, KaTeX and the Showdown”

  1. Thanks for your great guide ! I had been struggling through regular expressions until I saw your article. I've finally managed to get KaTeX and Markdown parsed at my just-another Math + Markdown preview page https://vincenttam.gitlab.io/math-live-preview/

Leave a Reply

Your email address will not be published. Required fields are marked *