wp_targeted_link_rel_callback

The timeline below displays how wordpress function wp_targeted_link_rel_callback has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 5.6

/**
 * Callback to add `rel="noopener"` string to HTML A element.
 *
 * Will not duplicate an existing 'noopener' value to avoid invalidating the HTML.
 *
 * @since 5.1.0
 * @since 5.6.0 Removed 'noreferrer' relationship.
 *
 * @param array $matches Single match.
 * @return string HTML A Element with `rel="noopener"` in addition to any existing values.
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the HTML escaped if there are no unescaped quotes.
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair(), leave the rest as is.
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string $rel       The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener', $link_html);
    // Return early if no rel values to be added or if no actual target attribute.
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = implode(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 5.4

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the HTML escaped if there are no unescaped quotes.
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair(), leave the rest as is.
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string $rel       The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute.
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 3.1

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string $rel       The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 5.3

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string $rel       The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } elseif (preg_match('|target\s*=\s*?\\\\"|', $link_html)) {
        $link_html .= " rel=\\\"{$rel}\\\"";
    } elseif (preg_match('#(target|href)\s*=\s*?\'#', $link_html)) {
        $link_html .= " rel='{$rel}'";
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: 2.5

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 2.3

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } elseif (preg_match('|target\s*=\s*?\\\\"|', $link_html)) {
        $link_html .= " rel=\\\"{$rel}\\\"";
    } elseif (preg_match('#(target|href)\s*=\s*?\'#', $link_html)) {
        $link_html .= " rel='{$rel}'";
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: .20

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 2.2

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } elseif (preg_match('|target\s*=\s*?\\\\"|', $link_html)) {
        $link_html .= " rel=\\\"{$rel}\\\"";
    } elseif (preg_match('#(target|href)\s*=\s*?\'#', $link_html)) {
        $link_html .= " rel='{$rel}'";
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: .10

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', array_column($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 2.1

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } elseif (preg_match('|target\s*=\s*?\\\\"|', $link_html)) {
        $link_html .= " rel=\\\"{$rel}\\\"";
    } elseif (preg_match('#(target|href)\s*=\s*?\'#', $link_html)) {
        $link_html .= " rel='{$rel}'";
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: 5.2

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @since 5.1.0
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: 1.4

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', wp_list_pluck($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 1.2

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}

WordPress Version: .10

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $original_link_html = $link_html;
    // Consider the html escaped if there are no unescaped quotes
    $is_escaped = !preg_match('/(^|[^\\\\])[\'"]/', $link_html);
    if ($is_escaped) {
        // Replace only the quotes so that they are parsable by wp_kses_hair, leave the rest as is
        $link_html = preg_replace('/\\\\([\'"])/', '$1', $link_html);
    }
    $atts = wp_kses_hair($link_html, wp_allowed_protocols());
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Return early if no rel values to be added or if no actual target attribute
    if (!$rel || !isset($atts['target'])) {
        return "<a {$original_link_html}>";
    }
    if (isset($atts['rel'])) {
        $all_parts = preg_split('/\s/', "{$atts['rel']['value']} {$rel}", -1, PREG_SPLIT_NO_EMPTY);
        $rel = implode(' ', array_unique($all_parts));
    }
    $atts['rel']['whole'] = 'rel="' . esc_attr($rel) . '"';
    $link_html = join(' ', wp_list_pluck($atts, 'whole'));
    if ($is_escaped) {
        $link_html = preg_replace('/[\'"]/', '\\\\$0', $link_html);
    }
    return "<a {$link_html}>";
}

WordPress Version: 5.1

/**
 * Callback to add rel="noreferrer noopener" string to HTML A element.
 *
 * Will not duplicate existing noreferrer and noopener values
 * to prevent from invalidating the HTML.
 *
 * @param array $matches Single Match
 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
 */
function wp_targeted_link_rel_callback($matches)
{
    $link_html = $matches[1];
    $rel_match = array();
    /**
     * Filters the rel values that are added to links with `target` attribute.
     *
     * @since 5.1.0
     *
     * @param string The rel values.
     * @param string $link_html The matched content of the link tag including all HTML attributes.
     */
    $rel = apply_filters('wp_targeted_link_rel', 'noopener noreferrer', $link_html);
    // Avoid additional regex if the filter removes rel values.
    if (!$rel) {
        return "<a {$link_html}>";
    }
    // Value with delimiters, spaces around are optional.
    $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\1|i';
    preg_match($attr_regex, $link_html, $rel_match);
    if (empty($rel_match[0])) {
        // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
        $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
        preg_match($attr_regex, $link_html, $rel_match);
    }
    if (!empty($rel_match[0])) {
        $parts = preg_split('|\s+|', strtolower($rel_match[2]));
        $parts = array_map('esc_attr', $parts);
        $needed = explode(' ', $rel);
        $parts = array_unique(array_merge($parts, $needed));
        $delimiter = trim($rel_match[1]) ? $rel_match[1] : '"';
        $rel = 'rel=' . $delimiter . trim(implode(' ', $parts)) . $delimiter;
        $link_html = str_replace($rel_match[0], $rel, $link_html);
    } else {
        $link_html .= " rel=\"{$rel}\"";
    }
    return "<a {$link_html}>";
}