tag.
*
* @package Postlinkly
* @since 1.0.0
*/
declare(strict_types=1);
namespace Postlinkly\Link;
/**
* Parses attributes out of an existing `` tag.
*
* Used during link removal and update operations to inspect what's
* already in the content. The parser is intentionally tolerant — it
* accepts both single- and double-quoted attribute values, ignores
* malformed input, and never throws.
*
* @since 1.0.0
*/
final class LinkAttributeParser {
/**
* Parses the attribute list out of an `` opening tag.
*
* Input may be either a complete tag (`y`) or just
* the opening tag (``). Anything that isn't an ``
* tag returns an empty array.
*
* @since 1.0.0
*
* @param string $tag The tag markup.
*
* @return array Map of lower-cased attribute name to raw value.
*/
public function parse( string $tag ): array {
// Capture the opening tag content between ``.
$matched = preg_match( '/]*)>/i', $tag, $m );
if ( 1 !== $matched || ! isset( $m[1] ) ) {
return array();
}
$inside = $m[1];
$out = array();
// Match name="value" or name='value' attributes.
if ( preg_match_all( '/([a-zA-Z][a-zA-Z0-9_:-]*)\s*=\s*("([^"]*)"|\'([^\']*)\')/', $inside, $matches, PREG_SET_ORDER ) ) {
foreach ( $matches as $match ) {
$name = strtolower( $match[1] );
$value = isset( $match[3] ) && '' !== $match[3] ? $match[3] : ( $match[4] ?? '' );
$out[ $name ] = $value;
}
}
return $out;
}
/**
* Returns whether a tag was created or modified by Postlinkly.
*
* Detected via the {@see LinkAttributeBuilder::PLUGIN_MARKER_ATTRIBUTE}
* attribute. Useful when the link-removal flow needs to skip links the
* user added by hand.
*
* @since 1.0.0
*
* @param string $tag The tag markup.
*
* @return bool
*/
public function is_plugin_link( string $tag ): bool {
$attrs = $this->parse( $tag );
return isset( $attrs[ LinkAttributeBuilder::PLUGIN_MARKER_ATTRIBUTE ] );
}
/**
* Returns the href value from a tag, or empty string when missing.
*
* @since 1.0.0
*
* @param string $tag The tag markup.
*
* @return string
*/
public function get_href( string $tag ): string {
$attrs = $this->parse( $tag );
return $attrs['href'] ?? '';
}
/**
* Returns the inner text of an `...` tag, or empty string on failure.
*
* Does not decode HTML entities — callers can apply `html_entity_decode`
* themselves when they need plain text.
*
* @since 1.0.0
*
* @param string $tag Complete `...` markup.
*
* @return string
*/
public function get_inner_text( string $tag ): string {
if ( 1 !== preg_match( '/]*>(.*?)<\/a>/is', $tag, $m ) ) {
return '';
}
return $m[1];
}
}