Changeset 12050 for sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/inc/formatting.php
- Timestamp:
- 09/05/2022 05:14:31 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/inc/formatting.php
r10493 r12050 40 40 add_filter( 'devhub-format-description', array( __CLASS__, 'fix_param_hash_formatting' ), 9 ); 41 41 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' ) ); 42 43 add_filter( 'devhub-format-description', array( __CLASS__, 'convert_lists_to_markup' ) ); 43 44 44 45 add_filter( 'devhub-format-hash-param-description', array( __CLASS__, 'autolink_references' ) ); 45 46 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' ) ); 46 49 47 50 add_filter( 'devhub-function-return-type', array( __CLASS__, 'autolink_references' ) ); 48 51 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( '&gt;', '>', $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 ); 61 67 } 62 68 … … 314 320 // Note: This precludes them from being able to be used in an encoded fashion 315 321 // within a parameter description. 316 $allowable_tags = array( 'code' );322 $allowable_tags = array( 'code', 'br' ); 317 323 foreach ( $allowable_tags as $tag ) { 318 324 $text = str_replace( array( "<{$tag}>", "</{$tag}>" ), array( "<{$tag}>", "</{$tag}>" ), $text ); … … 379 385 380 386 // 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, '->' ) ) { 382 388 383 389 // Detect references to class methods, e.g. WP_Query::query() … … 385 391 $content = preg_replace_callback( 386 392 '~ 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 (::|->|->) # Object reference 398 (\w+) # Method 399 (?P<after>\(\)| ) # () or whitespace to terminate. 400 ) 401 | 402 (?P<function>\w+\(\)) # Functions must always end in (). 391 403 ) 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. 394 405 ~x', 395 function ( $matches ) { 406 function( $matches ) { 407 $name = rtrim( $matches['name'], '() ' ); 408 $after = ( '()' === $matches['after'] ? '' : ' ' ); 409 396 410 // Reference to a class method. 397 if ( $matches[2] ) { 411 if ( $matches['class'] ) { 412 $name = str_replace( array( '->', '->' ), '::', $name ); 413 398 414 // 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' ) ) { 400 416 return sprintf( 401 '<a href="%s" >%s</a>',417 '<a href="%s" rel="method">%s</a>' . $after, 402 418 get_permalink( $post->ID ), 403 $ matches[0]419 $name . '()' 404 420 ); 405 421 } … … 408 424 } else { 409 425 // 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' ) ) { 411 427 return sprintf( 412 '<a href="%s" >%s</a>',428 '<a href="%s" rel="function">%s</a>' . $after, 413 429 get_permalink( $post->ID ), 414 $ matches[0]430 $name . '()' 415 431 ); 416 432 } … … 452 468 if ( $post = get_page_by_title( $matches[0], OBJECT, 'wp-parser-class' ) ) { 453 469 return sprintf( 454 '<a href="%s" >%s</a>',470 '<a href="%s" rel="class">%s</a>', 455 471 get_permalink( $post->ID ), 456 472 $matches[0] … … 484 500 * 485 501 * 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/ 486 507 * 487 508 * Does not handle nesting of lists. … … 491 512 */ 492 513 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. 530 530 531 531 return $text; … … 598 598 } 599 599 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>"; 603 603 if ( ! $skip_closing_li ) { 604 604 $new_text .= '</li>'; … … 671 671 } 672 672 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 } 673 821 } // DevHub_Formatting 674 822
Note: See TracChangeset
for help on using the changeset viewer.