From 187dc5f8340cfc38e61bf3dfa4b301fa25fb9d16 Mon Sep 17 00:00:00 2001
From: Paul Biron <paul@sparrowhawkcomputing.com>
Date: Wed, 30 May 2018 14:07:25 -0600
Subject: [PATCH] propose new filter for the attributes on an external link's
 anchor element.  @link https://meta.trac.wordpress.org/ticket/3649

---
 inc/formatting.php | 68 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 19 deletions(-)

diff --git a/inc/formatting.php b/inc/formatting.php
index 25921e2..5a5b13a 100644
--- a/inc/formatting.php
+++ b/inc/formatting.php
@@ -133,14 +133,16 @@ class DevHub_Formatting {
 
 					// Link without linked text: {@link http://en.wikipedia.org/wiki/ISO_8601}
 					if ( 1 === count( $parts ) ) {
-						$link = '<a href="' . esc_url( $link ) . '">' . esc_html( $link ) . '</a>';
+						$url = $text = $link;
 					}
 
 					// Link with linked text: {@link http://codex.wordpress.org/The_Loop Use new WordPress Loop}
 					else {
-						$link = '<a href="' . esc_url( $parts[0] ) . '">' . esc_html( $parts[1] ) . '</a>';
+						$url = $parts[0];
+						$text = $parts[1];
 					}
 
+					$link = self::generate_link( $url, $text );
 				}
 
 				// Link to an internal resource.
@@ -164,6 +166,8 @@ class DevHub_Formatting {
 	 * @return string HTML link markup if a valid element was found.
 	 */
 	public static function link_internal_element( $link ) {
+		$url = '';
+
 		// Link to class variable: {@see WP_Rewrite::$index}
 		if ( false !== strpos( $link, '::$' ) ) {
 			// Nothing to link to currently.
@@ -171,19 +175,15 @@ class DevHub_Formatting {
 
 		// Link to class method: {@see WP_Query::query()}
 		elseif ( false !== strpos( $link, '::' ) ) {
-			$link = '<a href="' .
-			        get_post_type_archive_link( 'wp-parser-class' ) .
-			        str_replace( array( '::', '()' ), array( '/', '' ), $link ) .
-			        '">' . esc_html( $link ) . '</a>';
+			$url = get_post_type_archive_link( 'wp-parser-class' ) .
+			        str_replace( array( '::', '()' ), array( '/', '' ), $link );
 		}
 
 		// Link to hook: {@see 'pre_get_search_form'}
 		elseif ( 1 === preg_match( '/^(?:\'|(?:&#8216;))([\$\w-&;]+)(?:\'|(?:&#8217;))$/', $link, $hook ) ) {
 			if ( ! empty( $hook[1] ) ) {
-				$link = '<a href="' .
-				        get_post_type_archive_link( 'wp-parser-hook' ) .
-				        sanitize_title_with_dashes( html_entity_decode( $hook[1] ) ) . '/' .
-				        '">' . esc_html( $link ) . '</a>';
+				$url = get_post_type_archive_link( 'wp-parser-hook' ) .
+				        sanitize_title_with_dashes( html_entity_decode( $hook[1] ) ) . '/';
 			}
 		}
 
@@ -196,24 +196,54 @@ class DevHub_Formatting {
 			||
 			( 1 === preg_match ( '/^_?[A-Z][a-zA-Z]+_\w+/', $link ) ) // Otherwise, class names start with (optional underscore, then) uppercase and have underscore
 		) {
-			$link = sprintf(
-				'<a href="%s">%s</a>',
-				esc_url( get_post_type_archive_link( 'wp-parser-class' ) . sanitize_key( $link ) ),
-				esc_html( $link )
-			);
+			$url = get_post_type_archive_link( 'wp-parser-class' ) . sanitize_key( $link );
 		}
 
 		// Link to function: {@see esc_attr()}
 		else {
-			$link = '<a href="' .
-					get_post_type_archive_link( 'wp-parser-function' ) .
-					sanitize_title_with_dashes( html_entity_decode( $link ) ) .
-					'">' . esc_html( $link ) . '</a>';
+			$url = get_post_type_archive_link( 'wp-parser-function' ) .
+					sanitize_title_with_dashes( html_entity_decode( $link ) );
+		}
+		
+		if ( $url ) {
+			$link = self::generate_link( $url, $link );
 		}
 		return $link;
 	}
 
 	/**
+	 * Generates a link given a URL and text.
+	 *
+	 * @since x.y.z
+	 *
+	 * @param string $url The URL, for the link's href attribute.
+	 * @param string $text The text content of the link.
+	 * @return string The HTML for the link.
+	 */
+	public static function generate_link( $url, $text ) {
+		/**
+		 * Filters the HTML attributes applied to a link's anchor element.
+		 *
+		 * @since x.y.z
+		 *
+		 * @param array $attrs The HTML attributes applied to the link's anchor element.
+		 * @param string $url The URL for the link.
+		 */
+		$attrs = apply_filters( 'devhub-format-link-attributes', array( 'href' => $url ), $url );
+		// make sure the filter didn't completely remove the href attribute
+		if ( empty( $attrs['href'] ) ) {
+			$attrs['href'] = $url;
+		}
+		$attributes = '';
+		foreach ( $attrs as $name => $value ) {
+			$value = 'href' === $name ? esc_url( $value ) : esc_attr( $value );
+			$attributes .= " $name='$value'";
+		}
+
+		return sprintf( '<a%s>%s</a>', $attributes, esc_html( $text ) );
+	}
+	
+	/**
 	 * Fixes unintended markup generated by Markdown during parsing.
 	 *
 	 * The parser interprets underscores surrounding text as Markdown indicating
-- 
2.7.0.windows.1

