Making WordPress.org


Ignore:
Timestamp:
09/05/2022 05:14:31 AM (3 years ago)
Author:
dufresnesteven
Message:

wporg-developer: Sync with https://github.com/WordPress/wporg-developer/commit/790d402933d2725374de0d19e6bf6a576c8b15d2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/inc/formatting.php

    r10493 r12050  
    4040        add_filter( 'devhub-format-description', array( __CLASS__, 'fix_param_hash_formatting' ), 9 );
    4141        add_filter( 'devhub-format-description', array( __CLASS__, 'fix_param_description_html_as_code' ) );
     42        add_filter( 'devhub-format-description', array( __CLASS__, 'fix_param_description_quotes_to_code' ) );
    4243        add_filter( 'devhub-format-description', array( __CLASS__, 'convert_lists_to_markup' ) );
    4344
    4445        add_filter( 'devhub-format-hash-param-description', array( __CLASS__, 'autolink_references' ) );
    4546        add_filter( 'devhub-format-hash-param-description', array( __CLASS__, 'fix_param_description_parsedown_bug' ) );
     47        add_filter( 'devhub-format-hash-param-description', array( __CLASS__, 'fix_param_description_quotes_to_code' ) );
     48        add_filter( 'devhub-format-hash-param-description', array( __CLASS__, 'convert_lists_to_markup' ) );
    4649
    4750        add_filter( 'devhub-function-return-type', array( __CLASS__, 'autolink_references' ) );
    4851
    49         add_filter( 'syntaxhighlighter_htmlresult', array( __CLASS__, 'fix_code_entity_encoding' ), 20 );
    50     }
    51 
    52     /**
    53      * Fixes bug in (or at least in using) SyntaxHighlighter code shortcodes that
    54      * causes double-encoding of `>` character.
    55      *
    56      * @param string $content The text being handled as code.
    57      * @return string
    58      */
    59     public static function fix_code_entity_encoding( $content ) {
    60         return str_replace( '>', '>', $content );
     52        add_shortcode( 'php', array( __CLASS__, 'do_shortcode_php' ) );
     53        add_shortcode( 'js', array( __CLASS__, 'do_shortcode_js' ) );
     54        add_shortcode( 'css', array( __CLASS__, 'do_shortcode_css' ) );
     55        add_shortcode( 'code', array( __CLASS__, 'do_shortcode_code' ) );
     56
     57        add_filter(
     58            'no_texturize_shortcodes',
     59            function ( $shortcodes ) {
     60                $shortcodes[] = 'php';
     61                $shortcodes[] = 'js';
     62                $shortcodes[] = 'css';
     63                $shortcodes[] = 'code';
     64                return $shortcodes;
     65            }
     66        );
    6167    }
    6268
     
    314320        // Note: This precludes them from being able to be used in an encoded fashion
    315321        // within a parameter description.
    316         $allowable_tags = array( 'code' );
     322        $allowable_tags = array( 'code', 'br' );
    317323        foreach ( $allowable_tags as $tag ) {
    318324            $text = str_replace( array( "&lt;{$tag}&gt;", "&lt;/{$tag}&gt;" ), array( "<{$tag}>", "</{$tag}>" ), $text );
     
    379385
    380386                // Only if the text contains something that might be a function.
    381                 if ( false !== strpos( $content, '()' ) ) {
     387                if ( str_contains( $content, '()' ) || str_contains( $content, '::' ) || str_contains( $content, '->' ) ) {
    382388
    383389                    // Detect references to class methods, e.g. WP_Query::query()
     
    385391                    $content = preg_replace_callback(
    386392                        '~
    387                             (?!<.*?)       # Non-capturing check to ensure not matching what looks like the inside of an HTML tag.
    388                             (              # 1: The full method or function name.
    389                                 ((\w+)::)? # 2: The class prefix, if a method reference.
    390                                 (\w+)      # 3: The method or function name.
     393                            (?!<.*?)                  # Non-capturing check to ensure not matching what looks like the inside of an HTML tag.
     394                            (?P<name>
     395                                (?P<class>
     396                                    (\w+)             # Class Name
     397                                    (::|->|-&gt;)     # Object reference
     398                                    (\w+)             # Method
     399                                    (?P<after>\(\)| ) # () or whitespace to terminate.
     400                                )
     401                                |
     402                                (?P<function>\w+\(\)) # Functions must always end in ().
    391403                            )
    392                             \(\)           # The () that signifies either a method or function.
    393                             (?![^<>]*?>)   # Non-capturing check to ensure not matching what looks like the inside of an HTML tag.
     404                            (?![^<>]*?>)              # Non-capturing check to ensure not matching what looks like the inside of an HTML tag.
    394405                        ~x',
    395                         function ( $matches ) {
     406                        function( $matches ) {
     407                            $name  = rtrim( $matches['name'], '() ' );
     408                            $after = ( '()' === $matches['after'] ? '' : ' ' );
     409
    396410                            // Reference to a class method.
    397                             if ( $matches[2] ) {
     411                            if ( $matches['class'] ) {
     412                                $name = str_replace( array( '->', '-&gt;' ), '::', $name );
     413
    398414                                // Only link actually parsed methods.
    399                                 if ( $post = get_page_by_title( $matches[1], OBJECT, 'wp-parser-method' ) ) {
     415                                if ( $post = get_page_by_title( $name, OBJECT, 'wp-parser-method' ) ) {
    400416                                    return sprintf(
    401                                         '<a href="%s">%s</a>',
     417                                        '<a href="%s" rel="method">%s</a>' . $after,
    402418                                        get_permalink( $post->ID ),
    403                                         $matches[0]
     419                                        $name . '()'
    404420                                    );
    405421                                }
     
    408424                            } else {
    409425                                // Only link actually parsed functions.
    410                                 if ( $post = get_page_by_title( $matches[1], OBJECT, 'wp-parser-function' ) ) {
     426                                if ( $post = get_page_by_title( $name, OBJECT, 'wp-parser-function' ) ) {
    411427                                    return sprintf(
    412                                         '<a href="%s">%s</a>',
     428                                        '<a href="%s" rel="function">%s</a>' . $after,
    413429                                        get_permalink( $post->ID ),
    414                                         $matches[0]
     430                                        $name . '()'
    415431                                    );
    416432                                }
     
    452468                        if ( $post = get_page_by_title( $matches[0], OBJECT, 'wp-parser-class' ) ) {
    453469                            return sprintf(
    454                                 '<a href="%s">%s</a>',
     470                                '<a href="%s" rel="class">%s</a>',
    455471                                get_permalink( $post->ID ),
    456472                                $matches[0]
     
    484500     *
    485501     * Recognizes lists where list items are denoted with an asterisk or dash.
     502     * Examples:
     503     * - https://developer.wordpress.org/reference/functions/add_menu_page/
     504     * - https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
     505     * - https://developer.wordpress.org/reference/hooks/password_change_email/
     506     * - https://developer.wordpress.org/reference/classes/WP_Query/parse_query/
    486507     *
    487508     * Does not handle nesting of lists.
     
    491512     */
    492513    public static function convert_lists_to_markup( $text ) {
    493         $inline_list = false;
    494         $li = '<br /> * ';
    495 
    496         // Convert asterisks to a list.
    497         // Example: https://developer.wordpress.org/reference/functions/add_menu_page/
    498         if ( false !== strpos( $text, ' * ' ) )  {
    499             // Display as simple plaintext list.
    500             $text = str_replace( ' * ', "\n" . $li, $text );
    501             $inline_list = true;
    502         }
    503 
    504         // Convert dashes to a list.
    505         // Example: https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
    506         // Example: https://developer.wordpress.org/reference/hooks/password_change_email/
    507         if ( false !== strpos( $text, ' - ' ) )  {
    508             // Display as simple plaintext list.
    509             $text = str_replace( ' - ', "\n" . $li, $text );
    510             $inline_list = true;
    511         }
    512 
    513         // If list detected.
    514         if ( $inline_list ) {
    515             // Replace first item, ensuring the opening 'ul' tag is prepended.
    516             $text = preg_replace( '~^' . preg_quote( $li ) . '(.+)$~mU', "<ul><li>\$1</li>\n", $text, 1 );
    517             // Wrap subsequent list items in 'li' tags.
    518             $text = preg_replace( '~^' . preg_quote( $li ) . '(.+)$~mU', "<li>\$1</li>\n", $text );
    519             $text = trim( $text );
    520 
    521             // Close the list if it hasn't been closed before start of next hash parameter.
    522             //$text = preg_replace( '~(</li>)(\s+</li>)~smU', '$1</ul>$2', $text );
    523             $text = preg_replace( '~(</li>)(\s*</li>)~smU', '$1</ul>$2', $text );
    524 
    525             // Closethe list if it hasn't been closed and it's the end of the description.
    526             if ( '</li>' === substr( trim( $text ), -5 ) ) {
    527                 $text .= '</ul>';
    528             }
    529         }
     514        // Expand new lines for ease of matching.
     515        $text = preg_replace( '!<br>\s*!', "<br>\n", $text );
     516
     517        // Trim any trailing <br>s on strings.
     518        $text = preg_replace( '/<br>\s*$/s', '', $text );
     519
     520        // Add line items
     521        $text = preg_replace( '!^\s*[*-] (.+?)(<br>)*$!m', '<li>$1</li>', $text, -1, $replacements_made );
     522
     523        if ( ! $replacements_made ) {
     524            return $text;
     525        }
     526
     527        // Wrap in a `ul`.
     528        $text = substr_replace( $text, '<ul><li>', strpos( $text, '<li>' ), 4 ); // First instance
     529        $text = substr_replace( $text, '</li></ul>', strrpos( $text, '</li>' ), 5 ); // Last instance.
    530530
    531531        return $text;
     
    598598                }
    599599                if ( $name ) {
    600                     $new_text .= "<b>'{$name}'</b><br />";
    601                 }
    602                 $new_text .= "<i><span class='type'>({$type})</span></i> {$description}";
     600                    $new_text .= "<code>{$name}</code>";
     601                }
     602                $new_text .= "<span class='type'>{$type}</span><div class='desc'>{$description}</div>";
    603603                if ( ! $skip_closing_li ) {
    604604                    $new_text .= '</li>';
     
    671671    }
    672672
     673    /**
     674     * Wraps code-like references within 'code' tags.
     675     *
     676     * Example: https://developer.wordpress.org/reference/classes/wp_term_query/__construct/
     677     *
     678     * @param string $text Text.
     679     * @return string
     680     */
     681    public static function fix_param_description_quotes_to_code( $text ) {
     682        // Don't do anything if this is a hash notation string.
     683        if ( ! $text || str_starts_with( $text, '{' ) || str_contains( $text, '<ul class="param-hash">' ) ) {
     684            return $text;
     685        }
     686
     687        $textarr     = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
     688        $text        = '';
     689        $within_code = false;
     690        foreach ( $textarr as $piece ) {
     691            // HTML tags are untouched.
     692            if ( str_starts_with( $piece, '<' ) || $within_code ) {
     693                $text .= $piece;
     694
     695                if ( str_starts_with( $piece, '</code' ) ) {
     696                    $within_code = false;
     697                } elseif ( ! $within_code ) {
     698                    $within_code = str_starts_with( $piece, '<code' );
     699                }
     700
     701                continue;
     702            }
     703
     704            // Pipe delimited types inline.
     705            $piece = preg_replace( "/(([\w'\[\]]+\|)+[\w'\[\]]+)/", '<code>$1</code>', $piece, -1 );
     706
     707            // Quoted strings.
     708            $piece = preg_replace( "/('[^' ]*')/", '<code>$1</code>', $piece, -1 );
     709
     710            // Replace ###PARAM### too.
     711            // Example: http://localhost:8888/reference/hooks/password_change_email/
     712            $piece = preg_replace( "/((#{2,})\w+\\2)/", '<code>$1</code>', $piece );
     713
     714            $text .= $piece;
     715        }
     716
     717        return $text;
     718    }
     719
     720    /**
     721     * Render the php shortcode using the Code Syntax Block syntax.
     722     *
     723     * This is a workaround for user-submitted code, which used the php shortcode from Syntax Highlighter Evolved.
     724     *
     725     * @param array|string $attr    Shortcode attributes array or empty string.
     726     * @param string       $content Shortcode content.
     727     * @param string       $tag     Shortcode name.
     728     * @return string
     729     */
     730    public static function do_shortcode_php( $attr, $content, $tag ) {
     731        $attr = is_array( $attr ) ? $attr : array();
     732        $attr['lang'] = 'php';
     733
     734        return self::do_shortcode_code( $attr, $content, $tag );
     735    }
     736
     737    /**
     738     * Render the js shortcode using the Code Syntax Block syntax.
     739     *
     740     * This is a workaround for user-submitted code, which used the js shortcode from Syntax Highlighter Evolved.
     741     *
     742     * @param array|string $attr    Shortcode attributes array or empty string.
     743     * @param string       $content Shortcode content.
     744     * @param string       $tag     Shortcode name.
     745     * @return string
     746     */
     747    public static function do_shortcode_js( $attr, $content, $tag ) {
     748        $attr = is_array( $attr ) ? $attr : array();
     749        $attr['lang'] = 'js';
     750
     751        return self::do_shortcode_code( $attr, $content, $tag );
     752    }
     753
     754    /**
     755     * Render the css shortcode using the Code Syntax Block syntax.
     756     *
     757     * This is a new shortcode, but built to mirror the above two, `js` & `php`.
     758     *
     759     * @param array|string $attr    Shortcode attributes array or empty string.
     760     * @param string       $content Shortcode content.
     761     * @param string       $tag     Shortcode name.
     762     * @return string
     763     */
     764    public static function do_shortcode_css( $attr, $content, $tag ) {
     765        $attr = is_array( $attr ) ? $attr : array();
     766        $attr['lang'] = 'css';
     767
     768        return self::do_shortcode_code( $attr, $content, $tag );
     769    }
     770
     771    /**
     772     * Render the code shortcode using the Code Syntax Block syntax.
     773     *
     774     * This is used in the handbooks content.
     775     *
     776     * @param array|string $attr    Shortcode attributes array or empty string.
     777     * @param string       $content Shortcode content.
     778     * @param string       $tag     Shortcode name.
     779     * @return string
     780     */
     781    public static function do_shortcode_code( $attr, $content, $tag ) {
     782        // Use an allowedlist of languages, falling back to PHP.
     783        // This should account for all languages used in the handbooks.
     784        $lang_list = [ 'js', 'json', 'sh', 'bash', 'html', 'css', 'scss', 'php', 'markdown', 'yaml' ];
     785        $lang = in_array( $attr['lang'], $lang_list ) ? $attr['lang'] : 'php';
     786
     787        $content = self::_trim_code( $content );
     788        // Hides numbers if <= 4 lines of code (last line has no linebreak).
     789        $show_line_numbers = substr_count( $content, "\n" ) > 3;
     790
     791        // Shell is flagged with `sh` or `bash` in the handbooks, but Prism uses `shell`.
     792        if ( 'sh' === $lang || 'bash' === $lang ) {
     793            $lang = 'shell';
     794        }
     795
     796        return do_blocks(
     797            sprintf(
     798                '<!-- wp:code {"lineNumbers":$3$s} --><pre class="wp-block-code"><code lang="%1$s" class="language-%1$s %4$s">%2$s</code></pre><!-- /wp:code -->',
     799                $lang,
     800                $content,
     801                $show_line_numbers ? 'true' : 'false',
     802                $show_line_numbers ? 'line-numbers' : ''
     803            )
     804        );
     805    }
     806
     807    /**
     808     * Trim off any extra space, including initial new lines.
     809     * Strip out <br /> and <p> added by WordPress.
     810     *
     811     * @param string $content Shortcode content.
     812     * @return string
     813     */
     814    public static function _trim_code( $content ) {
     815        $content = preg_replace( '/<br \/>/', '', $content );
     816        $content = preg_replace( '/<\/p>\s*<p>/', "\n\n", $content );
     817        // Trim everything except leading spaces.
     818        $content = trim( $content, "\n\r\t\v\x00" );
     819        return $content;
     820    }
    673821} // DevHub_Formatting
    674822
Note: See TracChangeset for help on using the changeset viewer.