Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 7
CRAP
n/a
0 / 0
latex_markup
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
latex_src
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
latex_get_default_color
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
latex_entity_decode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
latex_render
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
latex_shortcode
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
latex_no_texturize
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Module Name: Beautiful Math
4 * Module Description: Add beautifully formatted math equations to your posts and pages using LaTeX.
5 * Sort Order: 12
6 * First Introduced: 1.1
7 * Requires Connection: No
8 * Auto Activate: No
9 * Module Tags: Writing
10 * Feature: Writing
11 * Additional Search Queries: latex, math, equation, equations, formula, code
12 *
13 * @package automattic/jetpack
14 */
15
16if ( ! defined( 'ABSPATH' ) ) {
17    exit( 0 );
18}
19
20/**
21 * LaTeX support.
22 *
23 * Backward compatibility requires support for both "[latex][/latex]", and
24 * "$latex $" shortcodes.
25 *
26 * $latex e^{\i \pi} + 1 = 0$  ->  [latex]e^{\i \pi} + 1 = 0[/latex]
27 * $latex [a, b]$              ->  [latex][a, b][/latex]
28 */
29
30/**
31 * Markup LaTeX content.
32 *
33 * @param string $content Post or comment contents to markup.
34 */
35function latex_markup( $content ) {
36    if ( stripos( $content, '$latex' ) === false ) {
37        return $content;
38    }
39
40    $textarr = wp_html_split( $content );
41
42    $regex = '%
43        \$latex(?:=\s*|\s+)
44        ((?:
45            [^$]+ # Not a dollar
46        |
47            (?<=(?<!\\\\)\\\\)\$ # Dollar preceded by exactly one slash
48        )+)
49        (?<!\\\\)\$ # Dollar preceded by zero slashes
50    %ix';
51
52    foreach ( $textarr as &$element ) {
53        if ( '' === $element || '<' === $element[0] ) {
54            continue;
55        }
56
57        if ( false === stripos( $element, '$latex' ) ) {
58            continue;
59        }
60
61        $element = preg_replace_callback( $regex, 'latex_src', $element );
62    }
63
64    return implode( '', $textarr );
65}
66
67/**
68 * Process LaTeX string to rendered image.
69 *
70 * @param array $matches Matched regex results.
71 */
72function latex_src( $matches ) {
73    $latex = $matches[1];
74
75    $bg = latex_get_default_color( 'bg' );
76    $fg = latex_get_default_color( 'text', '000' );
77    $s  = 0;
78
79    $latex = latex_entity_decode( $latex );
80    if ( preg_match( '/.+(&fg=[0-9a-f]{6}).*/i', $latex, $fg_matches ) ) {
81        $fg    = substr( $fg_matches[1], 4 );
82        $latex = str_replace( $fg_matches[1], '', $latex );
83    }
84    if ( preg_match( '/.+(&bg=[0-9a-f]{6}).*/i', $latex, $bg_matches ) ) {
85        $bg    = substr( $bg_matches[1], 4 );
86        $latex = str_replace( $bg_matches[1], '', $latex );
87    }
88    if ( preg_match( '/.+(&s=[0-9-]{1,2}).*/i', $latex, $s_matches ) ) {
89        $s     = (int) substr( $s_matches[1], 3 );
90        $latex = str_replace( $s_matches[1], '', $latex );
91    }
92
93    return latex_render( $latex, $fg, $bg, $s );
94}
95
96/**
97 * Get the default color for an attribute.
98 *
99 * @param string $color Attribute to color (e.g. bg).
100 * @param string $default_color Default fallback color to use.
101 */
102function latex_get_default_color( $color, $default_color = 'ffffff' ) {
103    global $themecolors;
104    return $themecolors[ $color ] ?? $default_color;
105}
106
107/**
108 * Decode special characters in a LaTeX string.
109 *
110 * @param string $latex Character encoded content.
111 */
112function latex_entity_decode( $latex ) {
113    return str_replace( array( '&lt;', '&gt;', '&quot;', '&#039;', '&#038;', '&amp;', "\n", "\r" ), array( '<', '>', '"', "'", '&', '&', ' ', ' ' ), $latex );
114}
115
116/**
117 * Returns the URL for the server-side rendered image of LaTeX.
118 *
119 * @param string $latex LaTeX string.
120 * @param string $fg Foreground color.
121 * @param string $bg Background color.
122 * @param int    $s Matches.
123 *
124 * @return string Image URL for the rendered LaTeX.
125 */
126function latex_render( $latex, $fg, $bg, $s = 0 ) {
127    $url = add_query_arg(
128        urlencode_deep(
129            array(
130                'latex' => $latex,
131                'bg'    => $bg,
132                'fg'    => $fg,
133                's'     => $s,
134                'c'     => '20201002', // cache buster. Added 2020-10-02 after server migration caused faulty rendering.
135            )
136        ),
137        ( is_ssl() ? 'https://' : 'http://' ) . 's0.wp.com/latex.php'
138    );
139
140    $alt = str_replace( '\\', '&#92;', esc_attr( $latex ) );
141
142    return sprintf(
143        '<img src="%1$s" alt="%2$s" class="latex" />',
144        esc_url( $url ),
145        $alt
146    );
147}
148
149/**
150 * The shortcode way. The attributes are the same as the old ones - 'fg' and 'bg', instead of foreground
151 * and background, and 's' is for the font size.
152 *
153 * Example: [latex s=4 bg=00f fg=ff0]\LaTeX[/latex]
154 *
155 * @param array  $atts Shortcode attributes.
156 * @param string $content Content to format.
157 */
158function latex_shortcode( $atts, $content = '' ) {
159    $attr = shortcode_atts(
160        array(
161            's'  => 0,
162            'bg' => latex_get_default_color( 'bg' ),
163            'fg' => latex_get_default_color( 'text', '000' ),
164        ),
165        $atts,
166        'latex'
167    );
168
169    return latex_render( latex_entity_decode( $content ), $attr['fg'], $attr['bg'], $attr['s'] );
170}
171
172/**
173 * LaTeX needs to be untexturized.
174 *
175 * @param array $shortcodes Array of shortcodes not to texturize.
176 */
177function latex_no_texturize( $shortcodes ) {
178    $shortcodes[] = 'latex';
179    return $shortcodes;
180}
181add_filter( 'no_texturize_shortcodes', 'latex_no_texturize' );
182
183add_filter( 'the_content', 'latex_markup', 9 ); // Before wptexturize.
184add_filter( 'comment_text', 'latex_markup', 9 ); // Before wptexturize.
185add_shortcode( 'latex', 'latex_shortcode' );