diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 54883b840d7f4..6b6ebf87450a3 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -185,6 +185,11 @@ add_filter( $filter, 'shortcode_unautop' ); } +// Clickable content filters +add_filter( 'make_clickable', 'make_url_clickable', 2 ); +add_filter( 'make_clickable', 'make_ftp_clickable', 4 ); +add_filter( 'make_clickable', 'make_email_clickable', 6 ); + // Format for RSS. add_filter( 'term_name_rss', 'convert_chars' ); diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index 3ecc352528fec..7d6c65932f3ab 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -3106,31 +3106,7 @@ function make_clickable( $text ) { } } else { $ret = " $piece "; // Pad with whitespace to simplify the regexes. - - $url_clickable = '~ - ([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation. - ( # 2: URL. - [\\w]{1,20}+:// # Scheme and hier-part prefix. - (?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long. - [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character. - (?: # Unroll the Loop: Only allow punctuation URL character if followed by a non-punctuation URL character. - [\'.,;:!?)] # Punctuation URL character. - [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character. - )* - ) - (\)?) # 3: Trailing closing parenthesis (for parenthesis balancing post processing). - (\\.\\w{2,6})? # 4: Allowing file extensions (e.g., .jpg, .png). - ~xS'; - /* - * The regex is a non-anchored pattern and does not have a single fixed starting character. - * Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times. - */ - - $ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret ); - - $ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret ); - $ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret ); - + $ret = apply_filters( 'make_clickable', $ret ); $ret = substr( $ret, 1, -1 ); // Remove our whitespace padding. $r .= $ret; } @@ -3140,6 +3116,69 @@ function make_clickable( $text ) { return preg_replace( '#(]+?>|>))]+?>([^>]+?)#i', '$1$3', $r ); } +/** + * Converts URLs in text into clickable links. + * + * @since 6.8.0 + * @access private + * + * @param string $text The text to be processed. + * @return string Text with converted URLs. + */ +function make_url_clickable( $text ) { + $url_clickable = '~ + ([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation + ( # 2: URL + [\\w]{1,20}+:// # Scheme and hier-part prefix + (?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long + [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character + (?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character + [\'.,;:!?)] # Punctuation URL character + [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character + )* + ) + (\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing) + ~xS'; + + // The regex is a non-anchored pattern and does not have a single fixed starting character. + // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times. + return preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $text ); +} + +/** + * Converts FTP and www addresses in text into clickable links. + * + * @since 6.8.0 + * @access private + * + * @param string $text The text to be processed. + * @return string Text with converted FTP and www addresses. + */ +function make_ftp_clickable( $text ) { + return preg_replace_callback( + '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', + '_make_web_ftp_clickable_cb', + $text + ); +} + +/** + * Converts email addresses in text into clickable links. + * + * @since 6.8.0 + * @access private + * + * @param string $text The text to be processed. + * @return string Text with converted email addresses. + */ +function make_email_clickable( $text ) { + return preg_replace_callback( + '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', + '_make_email_clickable_cb', + $text + ); +} + /** * Breaks a string into chunks by splitting at whitespace characters. * diff --git a/tests/phpunit/tests/formatting/makeClickableFilters.php b/tests/phpunit/tests/formatting/makeClickableFilters.php new file mode 100644 index 0000000000000..63c21a1e15005 --- /dev/null +++ b/tests/phpunit/tests/formatting/makeClickableFilters.php @@ -0,0 +1,72 @@ +test@example.com'; + + $this->assertSame( $expected, make_clickable( $text ) ); + } + + /** + * @ticket 32787 + */ + public function test_remove_email_filter() { + remove_filter( 'make_clickable', 'make_email_clickable', 6 ); + + $text = 'Visit http://wordpress.org and test@example.com'; + $expected = 'Visit http://wordpress.org and test@example.com'; + + $this->assertSame( $expected, make_clickable( $text ) ); + } + + /** + * @ticket 32787 + */ + public function test_remove_ftp_filter() { + remove_filter( 'make_clickable', 'make_ftp_clickable', 4 ); + + $text = 'Visit ftp.wordpress.org and http://wordpress.org'; + $expected = 'Visit ftp.wordpress.org and http://wordpress.org'; + + $this->assertSame( $expected, make_clickable( $text ) ); + } + + /** + * @ticket 32787 + */ + public function test_remove_all_filters() { + remove_all_filters( 'make_clickable' ); + + $text = 'Visit http://wordpress.org, ftp.wordpress.org and test@example.com'; + $expected = 'Visit http://wordpress.org, ftp.wordpress.org and test@example.com'; + + $this->assertSame( $expected, make_clickable( $text ) ); + } +}