Make WordPress Core


Ignore:
Timestamp:
10/16/2018 04:12:21 AM (8 years ago)
Author:
peterwilsoncc
Message:

Formatting: Add pre-save content filter to make target=_blank always secure.

Props notnownikki, iseulde, azaozz.
Merges [42770] to the 5.0 branch.
Fixes #43187.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/5.0/src/wp-includes/formatting.php

    r43444 r43732  
    27722772        }
    27732773        return "<a $text rel=\"$rel\">";
     2774}
     2775
     2776/**
     2777 * Adds rel noreferrer and noopener to all HTML A elements that have a target.
     2778 *
     2779 * @param string $text Content that may contain HTML A elements.
     2780 * @return string Converted content.
     2781 */
     2782function wp_targeted_link_rel( $text ) {
     2783        // Don't run (more expensive) regex if no links with targets.
     2784        if ( stripos( $text, 'target' ) !== false && stripos( $text, '<a ' ) !== false ) {
     2785                $text = preg_replace_callback( '|<a\s([^>]*target\s*=[^>]*)>|i', 'wp_targeted_link_rel_callback', $text );
     2786        }
     2787
     2788        return $text;
     2789}
     2790
     2791/**
     2792 * Callback to add rel="noreferrer noopener" string to HTML A element.
     2793 *
     2794 * Will not duplicate existing noreferrer and noopener values
     2795 * to prevent from invalidating the HTML.
     2796 *
     2797 * @param array $matches Single Match
     2798 * @return string HTML A Element with rel noreferrer noopener in addition to any existing values
     2799 */
     2800function wp_targeted_link_rel_callback( $matches ) {
     2801        $link_html = $matches[1];
     2802        $rel_match = array();
     2803
     2804        /**
     2805         * Filters the rel values that are added to links with `target` attribute.
     2806         *
     2807         * @since 5.0.0
     2808         *
     2809         * @param string The rel values.
     2810         * @param string $link_html The matched content of the link tag including all HTML attributes.
     2811         */
     2812        $rel = apply_filters( 'wp_targeted_link_rel', 'noopener noreferrer', $link_html );
     2813
     2814        // Value with delimiters, spaces around are optional.
     2815        $attr_regex = '|rel\s*=\s*?(\\\\{0,1}["\'])(.*?)\\1|i';
     2816        preg_match( $attr_regex, $link_html, $rel_match );
     2817
     2818        if ( empty( $rel_match[0] ) ) {
     2819                // No delimiters, try with a single value and spaces, because `rel =  va"lue` is totally fine...
     2820                $attr_regex = '|rel\s*=(\s*)([^\s]*)|i';
     2821                preg_match( $attr_regex, $link_html, $rel_match );
     2822        }
     2823
     2824        if ( ! empty( $rel_match[0] ) ) {
     2825                $parts = preg_split( '|\s+|', strtolower( $rel_match[2] ) );
     2826                $parts = array_map( 'esc_attr', $parts );
     2827                $needed = explode( ' ', $rel );
     2828                $parts = array_unique( array_merge( $parts, $needed ) );
     2829                $delimiter = trim( $rel_match[1] ) ? $rel_match[1] : '"';
     2830                $rel = 'rel=' . $delimiter . trim( implode( ' ', $parts ) ) . $delimiter;
     2831                $link_html = str_replace( $rel_match[0], $rel, $link_html );
     2832        } else {
     2833                $link_html .= " rel=\"$rel\"";
     2834        }
     2835
     2836        return "<a $link_html>";
    27742837}
    27752838
Note: See TracChangeset for help on using the changeset viewer.